A - Good ol' Numbers Coloring

题意:有无穷个格子,给定 \(a,b\) ,按以下规则染色: \(0\) 号格子白色;当 \(i\) 为正整数, \(i\) 号格子当 \(i\geq a\) 且 \(i-a\) 是白色格子时涂白色;当 \(i\) 为正整数, \(i\) 号格子当 \(i\geq b\) 且 \(i-b\) 是白色格子时涂白色;仍不是白色的涂黑色,问黑色格子是否有无穷个。

题解:好像做过很多次了,遍历所有的整数的充要条件是这些拿来线性组合的步长的gcd为1。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
int T;
scanf("%d", &T);
while(T--) {
int a, b;
scanf("%d%d", &a, &b);
puts(__gcd(a, b) != 1 ? "Infinite" : "Finite");
}
}

B - Restricted RPS

题意:给定 \(a,b,c\) ,必须出 \(a\) 次Rock, \(b\) 次Paper, \(c\) 次Scissors,安排一个合理的顺序使得至少获胜一半的上整。

题解:贪心,直接构造。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; char s[105], t[105]; int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
int T;
scanf("%d", &T);
while(T--) {
int n, R, P, S;
scanf("%d%d%d%d%s", &n, &R, &P, &S, s + 1);
int cnt = 0;
for(int i = 1; i <= n; ++i) {
t[i] = '.';
if(s[i] == 'R') {
if(P) {
--P;
++cnt;
t[i] = 'P';
}
} else if(s[i] == 'P') {
if(S) {
--S;
++cnt;
t[i] = 'S';
}
} else {
if(R) {
--R;
++cnt;
t[i] = 'R';
}
}
}
if(cnt >= (n + 1) / 2) {
for(int i = 1; i <= n; ++i) {
if(t[i] == '.') {
if(P) {
--P;
t[i] = 'P';
} else if(S) {
--S;
t[i] = 'S';
} else {
--R;
t[i] = 'R';
}
}
}
t[n + 1] = '\0';
puts("YES");
puts(t + 1);
} else
puts("NO");
}
}

C - Constanze's Machine

题意:有一台听写机,会把你说的字母写下来,但是会把"w"写成"uu",并且会把"m"写成"nn",给一个字符串,求它可以由多少种原串经听写机翻译而成。

题解:很显然的一个dp,设 \(dp[i]\) 表示前 \(i\) 位形成的原串的种类数。遇到连续两个特殊字母则会从两个方向转移。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int MOD = 1e9 + 7; char s[100005];
int dp[100005]; int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
while(~scanf("%s", s + 1)) {
int n = strlen(s + 1);
dp[0] = 1;
for(int i = 1; i <= n; ++i) {
if(s[i] == 'w' || s[i] == 'm')
dp[i] = 0;
else if(i == 1 || s[i] != 'u' && s[i] != 'n')
dp[i] = dp[i - 1];
else if(s[i] == s[i - 1])
dp[i] = (dp[i - 1] + dp[i - 2]) % MOD;
else
dp[i] = dp[i - 1];
}
printf("%d\n", dp[n]);
}
}

注:这样写看起来好像会有bug,貌似 \(i-2\) 有可能会跳过那个0进行转移,但事实上不可能,因为必须要两个全等的"u"或者"n"才能跨步跳转,比如"mnn"这个串,并不会影响结果。

D - Shichikuji and Power Grid

题意:有 \(n\) 个城市,要给他们供电,直接给城市供电修建发电厂消耗 \(c_i\) 元,连接 \(i\) 城市和 \(j\) 城市的线路是曼哈顿距离,价格是每单位 \(k_i+k_j\) ,求最小价格使得所有城市都有电。

题解:好像和之前校内组队做的一个毁灭世界的很像,直接用最小生成树搞。方法是把 \(0\) 号节点和每个节点连一条权为 \(c_i\) 的边,然后“在这个城市修建发电厂”就等价于“从0号超级免费发电厂修价格为 \(c_i\) 的输电电路给这个城市供电”,转化成简单的最小生成树问题。

注:添加了0号节点之后,一开始是有 \(n+1\) 个连通块。记得要给多出来的边预留位置,应该是2000个吧,但是没关系直接开5e6就可以了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; int n;
int x[2005], y[2005];
int c[2005], k[2005]; struct Edge {
int u, v;
ll w;
Edge() {}
Edge(int uu, int vv, ll ww) {
u = uu, v = vv, w = ww;
}
bool operator<(const Edge &e)const {
return w < e.w;
}
} e[5000005]; int etop; int fa[2005], cnt; void init(int n) {
for(int i = 0; i <= n; ++i)
fa[i] = i;
cnt = n + 1;
} int find(int x) {
int r = fa[x], t;
while(fa[r] != r)
r = fa[r];
while(fa[x] != r) {
t = fa[x];
fa[x] = r;
x = t;
}
return r;
} bool merge(int x, int y) {
int fx = find(x), fy = find(y);
if(fx == fy)
return false;
fa[fx] = fy;
return true;
} vector<int> ans1;
vector<pair<int, int> > ans2; int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d%d", &x[i], &y[i]);
for(int i = 1; i <= n; ++i)
scanf("%d", &c[i]);
for(int i = 1; i <= n; ++i)
scanf("%d", &k[i]);
for(int i = 1; i <= n; ++i) {
e[++etop] = Edge(0, i, c[i]);
for(int j = i + 1; j <= n; ++j)
e[++etop] = Edge(i, j, (1ll * abs(x[i] - x[j]) + abs(y[i] - y[j])) * (1ll * k[i] + k[j]));
}
sort(e + 1, e + 1 + etop);
init(n); ll sumw = 0;
for(int i = 1; i <= etop && cnt > 1; ++i) {
int u = e[i].u, v = e[i].v;
ll w = e[i].w;
if(merge(u, v)) {
sumw += w;
if(u == 0)
ans1.push_back(v);
else
ans2.push_back({u, v});
}
}
printf("%lld\n", sumw);
// sort(ans1.begin(), ans1.end());
printf("%d\n", (int)ans1.size());
for(int i = 0, siz = ans1.size(); i < siz; ++i)
printf("%d%c", ans1[i], " \n"[i == siz - 1]);
// sort(ans2.begin(), ans2.end());
printf("%d\n", (int)ans2.size());
for(int i = 0, siz = ans2.size(); i < siz; ++i)
printf("%d %d\n", ans2[i].first, ans2[i].second);
}

标签:最小生成树,Kruskal算法

E - Hyakugoku and Ladders

题意:给一个10*10的方格图,从左下角走到右上角,路径是S型,图中有一些垂直的梯子,可以选择爬梯子或者不爬梯子,不能从梯子中间下来也不能换乘其他梯子(每一步最多只能走一个梯子),求最小期望。

细节:投出的骰子点数越界时,强制留在原地,否则强制前进骰子的点数。投点并尝试移动后在新位置假如是梯子底部则可以选择是否传送到该梯子的梯子顶部(每一步最多只能走一个梯子)。

题解:摆明了就是一个期望dp。麻烦的地方在于要给格子编号,然后用一个数组简单记录梯子传送去哪里,最后几步有可能会停留在原点造成循环转移。事实上这道题比F简单。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; int id[15][15], cg[15][15], g[105];
double dp[105];
bool vis[105]; double calc_dp(int p) {
if(vis[p])
return dp[p];
dp[p] = 0.0;
vis[p] = 1;
if(p >= 95) {
if(p == 100)
return dp[p];
double sum = 6.0;
for(int i = 1; i <= 100 - p; ++i)
sum += calc_dp(p + i);
sum /= 1.0 * (100 - p);
dp[p] = sum;
return dp[p];
}
double sum = 6.0;
for(int i = 1; i <= 6; ++i) {
if(g[p + i] == 0)
sum += calc_dp(p + i);
else
sum += min(calc_dp(p + i), calc_dp(g[p + i]));
}
sum /= 6.0;
dp[p] = sum;
return dp[p];
} int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
memset(vis, 0, sizeof(vis));
for(int i = 10; i >= 1; --i) {
for(int j = 1; j <= 10; ++j)
scanf("%d", &cg[i][j]);
}
int top = 0;
for(int i = 1; i <= 10; ++i) {
if(i & 1)
for(int j = 1; j <= 10; ++j)
id[i][j] = ++top;
else
for(int j = 10; j >= 1; --j)
id[i][j] = ++top;
} for(int i = 1; i <= 10; ++i) {
for(int j = 1; j <= 10; ++j) {
if(cg[i][j])
g[id[i][j]] = id[i + cg[i][j]][j];
}
} printf("%.10f\n", calc_dp(1));
}

标签:模拟,期望dp

F - Daniel and Spring Cleaning

题意:询问 \([l,r]\) 区间内有多少个数对 \((a,b)\) 满足 \(a+b=a \oplus b\) 。

思路:看起来就不能进位,这个不用多说,按直觉来看就是当 \(a,b\) 的二进制位1的位置不重复的时候才成立。这个形式就非常数位dp,再来一点场外因素肯定自己的猜测。但是至于怎么设状态还是不知道。

参考别人的题解:求区间中有多少个二元组满足条件就用二维容斥,具体为:设 \(f(a,b)\) 为满足 \(x+y=x \oplus y\) 且 \(0\leq x\leq a\) 且 \(0\leq y\leq b\) 的 \((x,y)\) 的数量,则答案为 \(f(l,r)=f(r,r)-2f(l-1,r)+f(l-1,l-1)\) 。剩下的直接抄模板。问题是什么才是二维数位dp的好模板呢?只能去偷别人的了。

这个数位dp就是直接连数位相关的的状态都没有的,因为每一位都是独立的,dfs下去的时候一直都保存合法的状态(i1&&j1直接被continue了),根据这么多年数位dp的经验,t肯定是表示这一位取值是否受限,而q是表示这一位是否可以取0作为开头(去掉也没关系,实测),而因为每次的限制位不一样所以对t值不为0的dp是不能重复使用的,不过为了方便全部设置成-1也可以(画蛇添足不记忆t状态就会TLE)。now==-1的时候返回的是越界之后(全部确定之后)还合法的数字的数量,在这里是恒为合法,直接返回1。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; ll dp[35][2][2][2][2], d1[35], d2[35]; inline ll dfs(ll now, int t1, int t2, int q1, int q2) {
if(now == -1)
return 1;
ll &res = dp[now][t1][t2][q1][q2];
if(res != -1)
return res;
res = 0;
int u1 = t1 ? d1[now] : 1, u2 = t2 ? d2[now] : 1;
for(int i = 0; i <= u1; i++)
for(int j = 0; j <= u2; j++) {
if(i == 1 && j == 1)
continue;
res += dfs(now - 1, t1 && (i == u1), t2 && (j == u2), q1 || (i != 0), q2 || (j != 0));
}
return res;
} inline ll calc(ll x, ll y) {
if(x < 0 || y < 0)
return 0;
memset(dp, -1, sizeof(dp));
for(ll i = 0; i <= 30; i++)
d1[i] = (x >> i) & 1;
for(ll i = 0; i <= 30; i++)
d2[i] = (y >> i) & 1;
return dfs(30, 1, 1, 0, 0);
} int main() {
#ifdef KisekiPurin
freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
int t;
scanf("%d", &t);
while(t--) {
ll l, r;
scanf("%lld%lld", &l, &r);
printf("%lld\n", calc(r, r) - 2ll * calc(l - 1, r) + calc(l - 1, l - 1));
}
}

标签:容斥原理,数位dp

参考资料:

[cf 1245 F] Daniel and Spring Cleaning - Fugtemypt - 博客园

Codeforces Round #597 (Div. 2)的更多相关文章

  1. Codeforces Round #597 (Div. 2) D. Shichikuji and Power Grid

    链接: https://codeforces.com/contest/1245/problem/D 题意: Shichikuji is the new resident deity of the So ...

  2. Codeforces Round #597 (Div. 2) C. Constanze's Machine

    链接: https://codeforces.com/contest/1245/problem/C 题意: Constanze is the smartest girl in her village ...

  3. Codeforces Round #597 (Div. 2) B. Restricted RPS

    链接: https://codeforces.com/contest/1245/problem/B 题意: Let n be a positive integer. Let a,b,c be nonn ...

  4. Codeforces Round #597 (Div. 2) A. Good ol' Numbers Coloring

    链接: https://codeforces.com/contest/1245/problem/A 题意: Consider the set of all nonnegative integers: ...

  5. Codeforces Round #597 (Div. 2) D. Shichikuji and Power Grid 题解 最小生成树

    题目链接:https://codeforces.com/contest/1245/problem/D 题目大意: 平面上有n座城市,第i座城市的坐标是 \(x[i], y[i]\) , 你现在要给n城 ...

  6. 计算a^b==a+b在(l,r)的对数Codeforces Round #597 (Div. 2)

    题:https://codeforces.com/contest/1245/problem/F 分析:转化为:求区间内满足a&b==0的对数(解释见代码) ///求满足a&b==0在区 ...

  7. Codeforces Round #597 (Div. 2) F. Daniel and Spring Cleaning 数位dp

    F. Daniel and Spring Cleaning While doing some spring cleaning, Daniel found an old calculator that ...

  8. Codeforces Round #597 (Div. 2) E. Hyakugoku and Ladders 概率dp

    E. Hyakugoku and Ladders Hyakugoku has just retired from being the resident deity of the South Black ...

  9. Codeforces Round #597 (Div. 2) D. Shichikuji and Power Grid 最小生成树

    D. Shichikuji and Power Grid</centerD.> Shichikuji is the new resident deity of the South Blac ...

  10. Codeforces Round #597 (Div. 2) C. Constanze's Machine dp

    C. Constanze's Machine Constanze is the smartest girl in her village but she has bad eyesight. One d ...

随机推荐

  1. Asp.Net Core 使用 MediatR

    Asp.Net Core 使用 MediatR 项目中使用了CQRS读写分离,增删改 的地方使用了 MediatR ,将进程内消息的发送和处理进行解耦.于是便有了这篇文章,整理并记录一下自己的学习.遇 ...

  2. Go 操作 Mysql(三)

    什么是事务? 事务是数据库非常重要的部分,它具有四大特性(原子性.一致性.隔离性.持久性) 以下内容出自<高性能MySQL>第三版,了解事务的ACID及四种隔离级有助于我们更好的理解事务运 ...

  3. 关于文本设置overflow:hidden后引起的垂直对齐问题

    目前有这样的需求,一行标题中,前面为图标,后面是文字,文字要实现一行省略的效果 首先把文字设为:display: inline-block; 然后设置省略: overflow: hidden; wor ...

  4. canvas 绘制动态圆环进度条

    由于使用的是vue开发,所以就展示一下绘制函数好了,上图是效果图 drawMain(drawing_elem, percent, forecolor, bgcolor) { /* @drawing_e ...

  5. mybatisplus 使用案例

    案例地址 https://github.com/qixianchuan/SpringBootQD/tree/master/mybatisplus

  6. 移动端调试工具Vconsole

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. zookeeper服务【-】windows安装与liunx安装

    windows安装zookeeper-3.4.14 https://www.apache.org/dyn/closer.cgi/zookeeper/ [zookeeper下载地址] 1.开启服务之前需 ...

  8. Laravel 队列的简单使用例子

    场景: 在一个a系统中注册一个用户时,发送请求到b系统中也注册一个相同信息的账号,考虑到网络有可能错误的原因,所以使用队列去处理 1.修改根目录 .env 文件的QUEUE_CONNECTION字段配 ...

  9. 图片处理:html文本获取图片Url,判断图片大小,存数据库

    1.从html文本获取图片Url /** * html文本中取出url链接 */ public class Url { public static void main(String[] args) { ...

  10. Vue 之 slot(插槽)

    前言: vue中关于插槽的文档说明很短,语言又写的很凝练,再加上其和methods,data,computed等常用选项在使用频率.使用先后上的差别,这就有可能造成初次接触插槽的开发者容易产生“算了吧 ...