Codeforces Round #597 (Div. 2)
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)的更多相关文章
- 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 ...
- Codeforces Round #597 (Div. 2) C. Constanze's Machine
链接: https://codeforces.com/contest/1245/problem/C 题意: Constanze is the smartest girl in her village ...
- 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 ...
- Codeforces Round #597 (Div. 2) A. Good ol' Numbers Coloring
链接: https://codeforces.com/contest/1245/problem/A 题意: Consider the set of all nonnegative integers: ...
- Codeforces Round #597 (Div. 2) D. Shichikuji and Power Grid 题解 最小生成树
题目链接:https://codeforces.com/contest/1245/problem/D 题目大意: 平面上有n座城市,第i座城市的坐标是 \(x[i], y[i]\) , 你现在要给n城 ...
- 计算a^b==a+b在(l,r)的对数Codeforces Round #597 (Div. 2)
题:https://codeforces.com/contest/1245/problem/F 分析:转化为:求区间内满足a&b==0的对数(解释见代码) ///求满足a&b==0在区 ...
- 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 ...
- 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 ...
- 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 ...
- 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 ...
随机推荐
- (面试题)请用C语言实现在32位环境下,两个无符号长整数相加的函数,相加之和不能存储在64位变量中
分析:长整数相加,将结果分为高位和低位部分,分别保存在两个32整数中. 比如:unsigned int a = 0xFFFFFFFF, unsigned int b = 0x1, 结果用unsigne ...
- 【转载】 Asp.Net MVC网站提交富文本HTML标签内容抛出异常
今天开发一个ASP.NET MVC网站时,有个页面使用到了FCKEditor富文本编辑器,通过Post方式提交内容时候抛出异常,仔细分析后得出应该是服务器阻止了带有HTML标签内容的提交操作,ASP. ...
- 微信小程序 swiper 组件坑
swiper 组件高度被限制为150px了,所以内容无法撑开. 解决办法 给这组件重新设置个高度,然后在把里面的图片设置为自动适应容器大小.图片模式设置为 宽度不变 自动适应高度 <swiper ...
- web前端如何优化自己的代码
前端的性能优化主要分为三部分: HTML优化 避免 HTML 中书写 CSS 代码,因为这样难以维护. 使用Viewport加速页面的渲染. 使用语义化标签,减少 CSS 代码,增加可读性和 SEO. ...
- windows 下 redis 的安装及使用
1.下载及安装redis 下载地址:https://github.com/dmajkic/redis/downloads 找到对应的版本下载安装 打开cmd窗口,用cd命令进入到安装redis的根目录 ...
- 在使用pandas获取网上数据报出url错误的解决办法
在使用pandas.read_csv('网址名')时,出现url错误是,需要在导包出添加一下两句代码 import ssl ssl._create_default_https_context = ss ...
- HTML基础之HTML常用标签
下面小编为大家整理一些HTML的常用标签 a.布局标签 div标签定义文档中的分区或节(division/section),可以把文档分割为独立的.不同的部分,主要用于布局. aside标签的内容可用 ...
- 列表推导式中的各个元素的id并不一样
列表推导式中的各个元素在不同的内存中,id不一样 # 列表推导式的不同id值 ----------------------------------------------------- T = [] ...
- sudo 权限的管理
一.sudo执行命令的流程将当前用户切换到超级用户下,或切换到指定的用户下,然后以超级用户或其指定切换到的用户身份执行命令,执行完成后,直接退回到当前用户.具体工作过程如下:当用户执行sudo时,系统 ...
- 数据库索引碎片——数据库sql
文章:检测和整理索引碎片 文章:[笔记整理]SQL Server 索引碎片 和 重建索引 文章介绍了检查表的索引碎片百分比 文章:[小问题笔记(八)] 常用SQL(读字段名,改字段名,打印影响行数,添 ...