CF补题 964-Div.4
CF补题 964-Div.4-20241206
Dashboard - Codeforces Round 964 (Div. 4) - Codeforces
A:
题目大意:给定一个两位数正整数 n ,求其位数之和
#include <stdio.h> int main() { int n; scanf("%d",&n); while(n--){ int x,sum=0; scanf("%d",&x); while(x!=0){ sum+=x%10; x/=10; } printf("%d\n",sum); } return 0; }
签到,简单的取各个位数然后计算
B:
题目大意:两人各有两张牌,每轮两人任意翻开其中一张,点数大的获胜,求第一个人能胜利的场数
#include <stdio.h> int main() { int t; scanf("%d", &t); while (t--) { int a1,a2, b1,b2; int win = 0; scanf("%d %d %d %d", &a1, &a2, &b1, &b2); if ((a1 > b1 && a2 >= b2) || (a1 >= b1 && a2 > b2)) win ++; if ((a1 > b2 && a2 >= b1) || (a1 >= b2 && a2 > b1)) win ++; printf("%d\n", win*2); } return 0; }
每次随机抽取两张中的一张,所以我们可以依次判断能获胜的情况
(a1 > b1 && a2 >= b2) || (a1 >= b1 && a2 > b2)
同位比较,能获胜的情况是:
选出的 a1
一定比 b1
大,那么保证能赢则需要 a2
不小于 b2
反之,选出的 a1
不小于 b1
,那么保证能赢则需要 a2
一定大于 b2
(a1 > b2 && a2 >= b1) || (a1 >= b2 && a2 > b1)
错位比较,能获胜的情况是:
选出的 a1
一定比 b2
大,那么保证能赢则需要 a2
不小于 b1
反之,选出的 a1
不小于 b2
,那么保证能赢则需要 a2
一定大于 b1
C:
题目大意:给出若干个区间,判断区间的间隙中是否存在解
#include <stdio.h> int l[200010], r[200010]; int main() { int t; scanf("%d", &t); while (t--) { int n, s, m;//n个区间 scanf("%d %d %d", &n, &s, &m); for (int i = 0; i < n; i++) scanf("%d %d", &l[i], &r[i]);//读入区间 int temp = 0, flag = 0;//定义变量,和状态标志 for (int i = 0; i < n; i++) { if (l[i] - temp >= s) {//当前的左区间减去上一个的右区间,为一个间隔 flag = 1;//若间隔大于我们要求的解 printf("YES\n");//能够满足题意输出yes break; } if (i == n - 1) {//对最后一个区间进行特判, if (m - r[i] >= s) {//如果能有解,则输出yes flag = 1; printf("YES\n"); break; } } temp = r[i];//将这次的右区间存到temp中,进入下一轮循环,计算间隔 } if (flag == 0) printf("NO\n");//如果遍历完仍然无解,则输出no } return 0; }
注意,需要将数据全部存进才能再进行判断
D:
题目大意:给出一个字符串(存在通配符?)和子串,判断子串是否在字符串的子序列中
#include <stdio.h> #include <string>//引用头文件 #include <iostream> using namespace std; int main() { int T; scanf("%d", &T); while (T--) { string s, t; cin >> s >> t;//读入string int i = 0, j = 0;//双指针 while (i < s.length() && j < t.length()) { //遍历两个字符串,遍历完s,或查找到了子序列就退出 if (s[i] == t[j]) i++, j++;//如果当前的字符相等,则把两个指针都往后移动 else if (s[i] == '?') s[i] = t[j], i++, j++;//如果当前s的字符为?,就赋值 else i++;//否则,移动i } for (int k = 0; k < s.length(); k++) { if (s[k] == '?') s[k] = 'a'; }//完善s序列 if (j == t.length())//如果j指向了t的最后元素,说明存在子序列 cout << "YES" << endl << s << endl;//输出yes和s else cout << "NO" << endl; } return 0; }
使用双指针维护两个字符串
这里的一个关键点:i
移动时,如果当前指向的元素之后能构成一个解,则这个元素之前的和它相同的元素也能构成一个解,例:
a b c c a g h l e
如果需要查找 ale
这个子序列,我们的 i
从 s[0]
开始,s[0]==t[0]
,但是下一位不相同,所以移动 i
往后查找一个元素使 s[i]==t[1]
,因为我们这时已经找到了一个元素和 t[0]
相同,在之后的过程中,只需要找剩余的元素即可
E:
题目大意:给出一个整数区间,我们可以对区间的任意两个数同时进行 *3
和 /3
操作,求使区间所有数变为 \(0\) 的最少操作数
#include <stdio.h> int a[200010],sum[200010]; void pre(){//预处理 for(int i=1;i <=200010;i++){ a[i]=a[i/3]+1;//递推 sum[i]=sum[i-1]+a[i];//前缀和 } } int main() { pre(); int T; scanf("%d", &T); while (T--) { int l, r; scanf("%d %d", &l, &r); printf("%d\n",sum[r]-sum[l-1]+a[l]);//计算总操作数 } return 0; }
采用暴力会严重超时,可以想到使用前缀和+预处理进行优化
由于我们的区间是 l~r
,其中的任意数都可以转化为 \(k+0,k+1,k+2,(k+1)+1,·····\) (\(k\) 为整除以 \(3\) 的商)
我们的 l
必然是 \(k+0,k+1,k+2\) 其中的一项,所以 l
通过 /3
的操作,取到 \(0\) 时,一定是操作最少的元素之一
而后,区间内的其他元素,通过已经为 \(0\) 的元素,再取到 \(0\) 会十分容易
由于我们对 l
进行 /3
时,某个其他元素会进行 *3
操作,故我们的总操作数为 所有元素/3
的操作数+l/3->0
的操作数
可以对所有区间内的数进行预处理,最后通过前缀和 \(O(1)\) 输出
F:逆元+组合数学,下次再学
G1:
题目大意:在数轴上缺失了一个数,这个数之前的数保持原样,这个数之后的数 \(+1\) ,通过至多 \(10\) 次询问,找到这个数
#include <iostream> using namespace std; int main() { int t; cin>>t; while(t--){ int l=1,r=999,ans,flag=0; while (l<r){ int mid=l+r>>1; cout<<"? 1 "<<mid<<endl; cin>>ans; if (ans>=2*mid){ cout<<"! 1"<<endl; flag=1; break; } if (ans==mid) l=mid+1; else r=mid; } if (!flag) cout<<"! "<<l<<endl; } return 0; }
一道互动题,使用 cout
和 endl
自动刷新缓冲区(不用 fflush
)
把矩形的面积转化为线的长度再二分查找(\(log_2{999}<10\) )
特别的,如果这个数为 \(1\) 时,我们查询的数一定会大于等于 mid
的两倍
正常:1 2 3 4 5 6 //l = 1 , mid = 3 缺失:2 3 4 5 6 7 //l` = 2 , mid = 3
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具