CF集萃2

时间:2022-06-20 02:10:24

CF1155D - Beautiful Array

题意:给你一个序列和x,你可以选择任意一个子串(可以为空)乘上x,使得得到的序列最大子串和最大。求这个最大值。30w,2s。

解:设fi,0/1/2表示序列前i个数还没乘x/正在乘x/乘完了x的最大后缀和。答案就是这个DP数组的最大值。

 #include <bits/stdc++.h>

 typedef long long LL;
const int N = ; LL a[N], x, f[N][];
int n; int main() {
scanf("%d%lld", &n, &x);
for(int i = ; i <= n; i++) {
scanf("%lld", &a[i]);
}
LL ans = ;
for(int i = ; i <= n; i++) {
f[i][] = std::max(a[i], f[i - ][] + a[i]);
f[i][] = std::max(std::max(a[i] * x, f[i - ][] + a[i] * x), f[i - ][] + a[i] * x);
f[i][] = std::max(a[i], std::max(f[i - ][] + a[i], f[i - ][] + a[i]));
ans = std::max(std::max(ans, f[i][]), std::max(f[i][], f[i][]));
}
printf("%lld\n", ans);
return ;
}

AC代码

本题还有一种线段树做法。从左往右扫一遍,在每个位置考虑乘x的那一段的右端点在当前位置时的最大值。

那么右边要加上一个最大前缀。左边要在线段树上每个位置,维护以当前位置为乘x左端时的最大值。就是最大后缀 + (x - 1)a[i]

然后求个最大值就行了。

CF1117C - Magic Ship

题意:你要从(x1,y1)到(x2,y2),你每天会走一格,还会被风吹一格。风向有个长为n的循环节。求最少要几天到达。n <= 1e5,坐标<=1e9。

解:发现某一天到达之后,接下来所有天都有办法到达。于是二分。

 #include <bits/stdc++.h>

 typedef long long LL;
const int N = ; int x1, x2, Y1, Y2, n;
char str[N];
int dx[N], dy[N]; template <typename T> inline T abs(T x) {
return x < ? -x : x;
} inline bool check(LL k) {
LL x = x1 + (k / n) * dx[n] + dx[k % n];
LL y = Y1 + (k / n) * dy[n] + dy[k % n];
return abs(x - x2) + abs(y - Y2) <= k;
} int main() {
scanf("%d%d%d%d", &x1, &Y1, &x2, &Y2); scanf("%d", &n);
scanf("%s", str + ); for(int i = ; i <= n; i++) {
dx[i] = dx[i - ];
dy[i] = dy[i - ];
if(str[i] == 'U') {
dy[i]++;
}
if(str[i] == 'D') {
dy[i]--;
}
if(str[i] == 'L') {
dx[i]--;
}
if(str[i] == 'R') {
dx[i]++;
}
} LL l = , r = 1e18;
while(l < r) {
LL mid = (l + r) >> ;
if(check(mid)) {
r = mid;
}
else {
l = mid + ;
}
} if(r == 1e18) r = -;
printf("%lld\n", r);
return ;
}

AC代码

CF1117D - Magic Gems

题意:你有很多个魔法宝石,每个可以变成m个普通宝石。你需要选出若干个魔法宝石,然后再选出若干个把它们变成普通宝石,以此来填满n个空格。问方案数。n <= 1e18,m <= 100。

解:枚举选多少个魔法宝石,发现答案其实就是这个东西:

CF集萃2

打表后发现fn = fn-1 + fn-m。然而我们还有一种更优秀的推法:考虑最后一个空位是普通宝石还是魔法宝石即可。矩阵快速幂即可。

 #include <bits/stdc++.h>

 typedef long long LL;
const int N = , MO = 1e9 + ; int a[N][N], c[N][N], m, ans[N][N];
LL n; inline void out(int (*a)[N]) { for(int i = ; i <= m; i++) {
for(int j = ; j <= m; j++) {
printf("%d ", a[i][j]);
}
puts("");
}
puts(""); return;
} inline void mul() {
memset(c, , sizeof(c));
for(int k = ; k <= m; k++) {
for(int i = ; i <= m; i++) {
if(!ans[i][k]) {
continue;
}
for(int j = ; j <= m; j++) {
c[i][j] = (c[i][j] + 1ll * ans[i][k] * a[k][j] % MO) % MO;
}
}
}
memcpy(ans, c, sizeof(ans));
return;
} inline void mulself() {
memset(c, , sizeof(c));
for(int k = ; k <= m; k++) {
for(int i = ; i <= m; i++) {
if(!a[i][k]) continue;
for(int j = ; j <= m; j++) {
c[i][j] = (c[i][j] + 1ll * a[i][k] * a[k][j] % MO) % MO;
}
}
}
memcpy(a, c, sizeof(c));
return;
} int main() {
scanf("%lld%d", &n, &m); if(n < m) {
printf("");
return ;
} for(int i = ; i < m; i++) {
a[i + ][i] = ;
}
a[][m] = a[m][m] = ;
for(int i = ; i <= m; i++) ans[i][i] = ; LL t = n - m;
//out(a);
//out(ans);
while(t) {
if(t & ) {
mul();
//out(ans);
}
mulself();
//out(a);
t = t >> ;
} int res = ;
for(int i = ; i <= m; i++) {
res = (res + ans[i][m]) % MO;
}
res = (res + ans[m][m]) % MO; printf("%d\n", res);
return ;
}

AC代码

CF1117E - Decypher the String

题意:存在一个长为n的字符串和n个swap操作,但是你都不知道。你只知道操作的结果。你可以询问三次,每次给定一个字符串,回答该字符串操作的结果。输出原串。n <= 10000。

解:可用的字符有26个。假如每次把集合s位置的字符变成a,那么操作后所有a的位置集合t和s之间就有一个双射。这样一次就可以把n / 26。发现26³ = 17576,刚好。

实现上就是用一个结构体表示一组双射,两个vector存s和t。每次把这个vector分段染色,然后输出,操作完之后进行分组。

 #include <bits/stdc++.h>

 const int N = ;
/// 26 * 26 = 676
struct Node {
std::vector<int> a, b;
}stk[N]; int top; char str[N], my[N];
int n; inline void solve(const Node &x) {
int lm;
if(x.a.size() <= ) {
lm = ;
}
else if(x.a.size() <= ) {
lm = ;
}
else {
lm = ;
}
int p = ;
char c = 'a';
for(int i = ; i < (int)x.a.size(); i++) {
my[x.a[i]] = c;
++p;
if(p == lm) {
p = ;
++c;
}
}
return;
} inline void work(int i) {
int lm;
if(stk[i].a.size() <= ) {
lm = ;
}
else if(stk[i].a.size() <= ) {
lm = ;
}
else {
lm = ;
}
int p = , cnt = , f;
for(int j = ; j < (int)stk[i].a.size(); j++) {
stk[top + cnt].a.push_back(stk[i].a[j]);
++p;
f = cnt;
if(p == lm) {
p = ;
++cnt;
}
} for(int j = ; j < (int)stk[i].a.size(); j++) {
int x = stk[i].b[j];
stk[top + - 'a' + my[x]].b.push_back(x);
}
stk[i] = stk[top + f];
stk[top + f].a.clear(); /// !!! important
stk[top + f].b.clear(); ///
top = top + f - ;
return;
} int main() {
scanf("%s", str + );
n = strlen(str + ); top = ;
for(int i = ; i <= n; i++) {
stk[].a.push_back(i);
stk[].b.push_back(i);
my[i] = 'a';
} for(int t = ; t <= ; t++) {
//printf("t = %d \n", t);
for(int i = ; i <= top; i++) {
//printf("i = %d \n", i);
if(stk[i].a.size() > ) {
solve(stk[i]);
}
}
printf("? ");
for(int i = ; i <= n; i++) {
putchar(my[i]);
}
puts("");
fflush(stdout);
scanf("%s", my + );
int temp = top;
for(int i = ; i <= temp; i++) {
if(stk[i].a.size() > ) {
work(i);
}
}
} for(int i = ; i <= n; i++) {
my[stk[i].a[]] = str[stk[i].b[]];
}
printf("! ");
for(int i = ; i <= n; i++) {
putchar(my[i]);
}
puts("");
return ;
}

AC代码

这题还有一种CRT解法......

具体来说,对每个位置i,考虑它是从哪来的,设从pos来。

那么我们先询问三次,如下图。

CF集萃2

然后那么对于i来说,pos % 23 = s1[i] - 'a'。然后解方程即可。

CF1146G Zoning Restrictions

题意:你要在长为n的位置上填上[0, h]的数,如果填了x就会得到x2块钱。有m个限制,形如如果在[l, r]中有数超过了y,就要付c块钱。求最多钱数。n,m,h <= 50。

解:有一种网络流做法是最小割。

考虑切糕,把每个位置的取值都串起来,因为要最小,就先假设填了h,填x就是h2 - x2。对于限制,额外连向一个新点,向t连边为c。

 #include <bits/stdc++.h>

 const int N = , INF = 0x3f3f3f3f;

 struct Edge {
int nex, v, c;
Edge(){}
Edge(int N, int V, int C) {
nex = N;
v = V;
c = C;
}
}edge[]; int tp = ; int e[N], n, h, m, vis[N], d[N];
std::queue<int> Q; inline void add(int x, int y, int z) {
edge[++tp] = Edge(e[x], y, z);
e[x] = tp;
edge[++tp] = Edge(e[y], x, );
e[y] = tp;
return;
} inline bool BFS(int s, int t) {
static int Time = ;
Q.push(s);
++Time;
vis[s] = Time;
d[s] = ;
while(Q.size()) {
int x = Q.front();
Q.pop();
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(vis[y] != Time && edge[i].c) {
vis[y] = Time;
d[y] = d[x] + ;
Q.push(y);
}
}
}
return vis[t] == Time;
} int DFS(int x, int t, int maxF) {
if(x == t) {
return maxF;
}
int ans = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(d[x] + != d[y] || !edge[i].c) {
continue;
}
int temp = DFS(y, t, std::min(maxF - ans, edge[i].c));
if(!temp) {
d[y] = INF;
}
ans += temp;
edge[i].c -= temp;
edge[i ^ ].c += temp;
if(ans == maxF) {
break;
}
}
return ans;
} inline int solve(int s, int t) {
int ans = ;
while(BFS(s, t)) {
ans += DFS(s, t, INF);
}
return ans;
} inline int id(int x, int y) {
return (x - ) * (h + ) + y + ;
} int main() { scanf("%d%d%d", &n, &h, &m);
int s = (h + ) * n + m + , t = s + , lm = (h + ) * n, V = h * h;
for(int i = ; i <= n; i++) {
add(s, id(i, ), INF);
add(id(i, h + ), t, INF);
for(int j = ; j <= h; j++) {
add(id(i, j), id(i, j + ), V - j * j);
}
}
for(int i = ; i <= m; i++) {
int l, r, x, y;
scanf("%d%d%d%d", &l, &r, &x, &y);
if(x == h) continue;
int p = lm + i;
add(p, t, y);
for(int j = l; j <= r; j++) {
add(id(j, x + ), p, INF);
}
} int ans = n * h * h;
ans -= solve(s, t);
printf("%d\n", ans);
return ;
}

AC代码

还有一种区间DP解法,我并不会...

CF1147D - Palindrome XOR

题意:求有多少对长度不超过n的无前导0的回文01串满足异或起来恰好为s。s的第一位一定是1,存在通配符。n <= 1000

解:这个1000很有趣....可以O(n)枚举第二个串的开头在哪。

然后发现这个回文和异或都是些形如“它们相等”或者“它们不等”的限制。于是考虑用并查集处理这些限制,每个连通块有两种取值。边带权并查集即可。

 #include <bits/stdc++.h>

 const int N = , MO = ;

 char str[N];
int n; inline int qpow(int a, int b) {
int ans = ;
while(b) {
if(b & ) ans = 1ll * ans * a % MO;
a = 1ll * a * a % MO;
b = b >> ;
}
return ans;
} namespace ufs {
int cnt, fa[N * ], val[N * ];
inline void init() {
for(int i = ; i <= n * + ; i++) {
fa[i] = i;
val[i] = ;
}
cnt = * n;
return;
}
int find(int x, int &v) {
if(x == fa[x]) {
v = ;
return x;
}
int t = find(fa[x], v);
v ^= val[x];
fa[x] = t;
val[x] = v;
return t;
}
inline bool merge(int x, int y, int v) {
int t, t2;
x = find(x, t);
y = find(y, t2);
t ^= t2;
if(x == y) {
if(t != v) return false;
return true;
}
else {
fa[x] = y;
val[x] = v ^ t;
cnt--;
}
return true;
}
}
using ufs::merge; int main() {
scanf("%s", str + );
n = strlen(str + );
std::reverse(str + , str + n + );
int ans = , Z = * n + ;
for(int i = n - ; i >= ; i--) {
ufs::init();
if(!merge(n, Z, )) continue;
if(!merge(, Z, )) continue;
if(!merge(n + , Z, )) continue;
if(!merge(n + i, Z, )) continue;
int fd = ;
for(int j = n; j > i; j--) {
if(!merge(n + j, Z, )) {
fd = ; break;
}
}
if(fd) continue;
for(int j = ; j * <= n; j++) {
if(!merge(j, n - j + , )) {
fd = ;
break;
}
}
if(fd) continue;
for(int j = ; j * <= i; j++) {
if(!merge(n + j, n + i - j + , )) {
fd = ;
break;
}
}
if(fd) continue;
for(int j = ; j <= n; j++) {
if(str[j] != '?') {
if(!merge(j, n + j, str[j] - '')) {
fd = ;
break;
}
}
}
if(fd) continue;
ans = (ans + qpow(, ufs::cnt)) % MO;
}
printf("%d\n", ans);
return ;
}

AC代码

CF集萃2的更多相关文章

  1. CF集萃1

    因为cf上一堆水题,每个单独开一篇博客感觉不太好,就直接放一起好了. CF1096D Easy Problem 给定字符串,每个位置删除要代价.求最小代价使之不含子序列"hard" ...

  2. CF集萃3

    CF1118F2 - Tree Cutting 题意:给你一棵树,每个点被染成了k种颜色之一或者没有颜色.你要切断恰k - 1条边使得不存在两个异色点在同一连通块内.求方案数. 解:对每颜色构建最小斯 ...

  3. ORA-00494&colon; enqueue &lbrack;CF&rsqb; held for too long &lpar;more than 900 seconds&rpar; by 'inst 1&comma; osid 5166'

    凌晨收到同事电话,反馈应用程序访问Oracle数据库时报错,当时现场现象确认: 1. 应用程序访问不了数据库,使用SQL Developer测试发现访问不了数据库.报ORA-12570 TNS:pac ...

  4. cf之路,1,Codeforces Round &num;345 &lpar;Div&period; 2&rpar;

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  5. cf Round 613

    A.Peter and Snow Blower(计算几何) 给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积.保证这个点不在多边形内. 画个图能明白 这个图形是一个圆环,那么就是这个 ...

  6. ARC下OC对象和CF对象之间的桥接&lpar;bridge&rpar;

    在开发iOS应用程序时我们有时会用到Core Foundation对象简称CF,例如Core Graphics.Core Text,并且我们可能需要将CF对象和OC对象进行互相转化,我们知道,ARC环 ...

  7. &lbrack;Recommendation System&rsqb; 推荐系统之协同过滤(CF)算法详解和实现

    1 集体智慧和协同过滤 1.1 什么是集体智慧(社会计算)? 集体智慧 (Collective Intelligence) 并不是 Web2.0 时代特有的,只是在 Web2.0 时代,大家在 Web ...

  8. CF memsql Start&lbrack;c&rsqb;UP 2&period;0 A

    CF memsql Start[c]UP 2.0 A A. Golden System time limit per test 1 second memory limit per test 256 m ...

  9. CF memsql Start&lbrack;c&rsqb;UP 2&period;0 B

    CF memsql Start[c]UP 2.0 B B. Distributed Join time limit per test 1 second memory limit per test 25 ...

随机推荐

  1. 安装SqlServer的时候性能计数器注册表配置单元一致性失败的解决办法

    http://www.2cto.com/database/201204/126772.html

  2. PowerDesigner的使用二

    PowerDesigner是一款功能非常强大的建模工具软件,足以与Rose比肩,同样是当今 最著名的建模软件之一.Rose是专攻UML对象模型的建模工具,之后才向数据库建模发展,而PowerDesig ...

  3. STM32 USB CAN 学习笔记 - 共享RAM的用法

    USB 时钟可以一直使能. 如果CAN时钟没有使能,RAM 能被软件读写.(CANBus 不能发送和接受Message) 如果CAN时钟使能,RAM不能软件被写. CANBus Core 控制此RAM ...

  4. java 使用正则表达式对文件名非法字符处理

    1.文件名在操作系统中不允许出现  / \ " : | * ? < > 故将其以空替代       Pattern pattern = Pattern.compile(&quot ...

  5. Warning&colon; session&lowbar;start&lpar;&rpar; &lbrack;function&period;session-start&rsqb;&colon; Cannot send session cookie - headers already sent by

    配置php网站的时候,经常会在页首出现Warning: session_start() [function.session-start]: Cannot send session cache limi ...

  6. Netty中的连接管理

    连接管理是我们首先需要关注的,检测空闲连接以及超时对于及时释放资源来说是至关重要的.由于这是一项常见的任务,Netty特地为它提供了几个ChannelHandler实现. 用于空闲连接以及超时的Cha ...

  7. asp&period;net core 系列 10 配置configuration &lpar;上&rpar;

    一.  ASP.NET Core 中的配置概述 ASP.NET Core 中的应用配置是基于键值对,由configuration 程序提供. configuration  将从各种配置源提供程序操作键 ...

  8. 导出pdf功能

    本程序下载地址: PDF是我们极其常用的文件格式,但对如何生成PDF,个人一直觉得很神秘,其实利用一些公开的PDF库,我们就可以直接生成PDF文件,而不用关注PDF文件的内部细节.我知道的PDF库有如 ...

  9. &star; &lbrack;HDU2157&rsqb; How many ways&quest;&quest; 「矩阵乘法求路径方案数」

    传送门:>Here< 题意:给出一张有向图,问从点A到点B恰好经过k个点(包括终点)的路径方案数 解题思路 一道矩阵乘法的好题!妙哉~ 话说把矩阵乘法放在图上好神奇,那么跟矩阵唯一有关的就 ...

  10. vc&plus;&plus;基础班&lbrack;22&rsqb;---文件的基本操作2

      MFC 中的 CFile 及其派生类中没有提供直接进行文件的复制操作,因而要借助于SDK API: SDK中的文件相关函数常用的有CopyFile().CreateDirectory().Dele ...