Educational Codeforces Round 74 (Rated for Div. 2)
A. Prime Subtraction (CF 1238 A)
题目大意
给定,问它们的差能否表示成质数和。
解题思路
任何大于数都可以做质因数分解,那么只要差不是,都是可以的。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { int kase; read(kase); for (int i = 1; i <= kase; i++) { LL a,b; read(a); read(b); if (a-b==1) puts("NO"); else puts("YES"); } return 0; }
B. Kill 'Em All (CF 1238 B)
题目大意
给定,在一维数轴上,有个怪物位置分别在,现可以扔一个炸弹到某位置,位置的怪物就挂了,小于的会后退单位,即坐标变为,大于的会前进单位,即坐标变为。若怪物坐标小于等于则怪物也挂了。问最少扔多少个炸弹使得所有怪物都挂了。
解题思路
如果任意扔中间位置,原点远的怪物会越来越远,这时要不直接打它,要不用冲击波让它飞到小于等于处这显然不是最优的。显然贪心每次打最远的怪物直到所有怪物的坐标都小于等于0或者所有怪物都挂了。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { int kase; read(kase); for (int i = 1; i <= kase; i++) { int n; LL r; vector<LL> pos; bool sign[100005]={0}; read(n); read(r); for(int u,i=1;i<=n;++i){ read(u); if (!sign[u]){ pos.push_back(u); sign[u]=true; } } sort(pos.begin(),pos.end(),greater<int>()); LL cnt=0; for(auto i:pos){ if (i-cnt*r<=0) break;; ++cnt; } write(cnt,'\n'); } return 0; }
C. Standard Free2play (CF 1238 C)
题目大意
给定,表示初始高度为,初始有块板高度分别为是伸出来的,你需要从到地面(高度为),当站上一块板后,该板和下一块板的状态会发生改变,即从伸出来变成缩进去,或者从缩进去变成伸出来。你一次最多可以掉落两个高度单位。问初始最少需要改变多少块板的状态,你才能安全到达地面。
解题思路
手玩几个样例会发现,初始如果有连续偶数个板伸出来,这时候需要改变一个板的状态,可以改变最后一个伸出来的或者最后一个伸出来的下一块板的状态,使得这个连续板伸出来的数量为偶数。而对于中间如果有连续奇数个板伸出来,这时候也需要改变一块板的状态。问题就转换成统计连续板的奇偶性问题了。注意与地面连接的连续板的那部分不需要考虑。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { int kase; read(kase); for (int i = 1; i <= kase; i++) { int n,h; read(h); read(n); int cnt=0; int la; read(la); int ans=0; for(int v,i=2;i<=n;++i){ read(v); if (la-v==1) ++cnt; else{ if (cnt&1) ++ans; cnt=1; } la=v; } if (la-0==1) ++cnt; else if (cnt&1) ++ans; if (h==1) ans=0; write(ans,'\n'); } return 0; }
D. AB-string (CF 1238 D)
题目大意
给定一个长度为的串,问串有多少个子串是好串。一个串是好串当且仅当它的每个字母都在某个回文子串中。
解题思路
直接统计会爆时间,考虑每个回文串去统计对答案的贡献比较难,但发现统计不是好串的数量十分容易,我们可以容斥。
由于串中仅包含,我们考虑一段连续的长度为的子串,记为,它的右边一位是,则不是好串,减去前面若干个后也不是好串,这时不是好串的数量有个,如果后面是,则是好串。而如果后面是,则还是个好串。所以不是好串的子串都是形如或者,当然也有或者,所以前扫一遍后扫一遍即可得出答案。注意长度为的不是好串的串重复统计的情况。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { int n; read(n); char s[n]; scanf("%s",s); LL ans=(LL)n*(n+1)/2; int cnt=1; for(int i=1;i<n;++i){ if (s[i]==s[i-1]) ++cnt; else{ ans-=cnt; cnt=1; } } cnt=1; for(int i=n-1;i>=0;--i){ if (s[i]==s[i+1]) ++cnt; else{ ans-=cnt-1; cnt=1; } } ans-=n; write(ans,'\n'); return 0; }
E. Keyboard Purchase (CF 1238 E)
题目大意
给定,以及长度为的仅包含字母表前个的串,现在需要重新安排这前个字母的顺序,排成一列,使得输入这个串的代价最小。输入串的代价为手指需要移动的距离。
解题思路
考虑暴力,即枚举排列的情况分别计算,我们发现这很像数位。由于,我们可以状压,设表示我们已经排好的字母的状态下,剩下的字母排列的所有情况中,需要的最小代价。由于在二进制中的数量暗示了当前要填的数的位置,我们枚举当前位置要填的一个字母,考虑填这个字母后它所贡献的代价,即为,其中表示在串中,字母相邻的次数。但由于的位置从我们设置的状态中无法得知,或者还没填进去。但我们把因子乘进去,我们可以分别计算两者的贡献,即填的时候,我们把放进答案,当填的时候,我们再把放进答案,这样就组成了。所以我们填后,对于已经填进去的字母我们把放进答案,而没出现的,就把放进答案。记忆化搜索即可。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } const int N=1e5+8; const LL INF=1e9+7; int n,m; char s[N]; LL dp[1<<20]; int cnt[27][27]; void solve(int cur,int num){ if (cur==(1<<m)-1) return; if (dp[cur]!=INF) return; for(int i=0;i<m;++i){ if ((cur>>i)&1) continue; LL qwq=0; for(int j=0;j<m;++j){ if (i==j) continue; if ((cur>>j)&1) qwq+=cnt[i][j]*num; else qwq-=cnt[i][j]*num; } solve(cur|(1<<i),num+1); dp[cur]=min(dp[cur],dp[cur|(1<<i)]+qwq); } } int main(void) { read(n); read(m); scanf("%s",s); int len=strlen(s); for(int i=1;i<len;++i){ ++cnt[s[i-1]-'a'][s[i]-'a']; ++cnt[s[i]-'a'][s[i-1]-'a']; } for(int i=0;i<(1<<m);++i) dp[i]=INF; dp[(1<<m)-1]=0; solve(0,1); write(dp[0],'\n'); return 0; }
F. The Maximum Subtree (CF 1238 F)
题目大意
给定一棵树,要求找出最大的子树,使得该子树可以通过给定的方法构造出来。给定的方法为,选择一些线段,它们分别代表一个点,如果线段之间有交点,它们点与点之间有连线,然后这些线段所形成的图是你选定的子树。
解题思路
我们先考虑由线段构成的树会有什么性质。
容易发现这种树它的任意一个点所连的所有点中,最多只能有两个点有孩子。
然后就是一个找带权的最大直径问题,这个权是某点所连接的无孩子的点的数量。
或者可以采用树型,如果我们强行规定一个根,那么根可以有两个孩子有孙子,其余的仅可以有一个孩子有孙子。表示以为根的子树的最大子树,表示以父亲为根,子树的最大子树。
则,其中表示点的度,表示的所有孩子中,的最大值和次大值。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } void DFS(int u,int fa,vector<int> edge[],vector<int> °,int dp[][2]){ int ma=0,sma=0; for(int v:edge[u]){ if (v==fa) continue; DFS(v,u,edge,deg,dp); if (dp[v][1]>=ma){ sma=ma; ma=dp[v][1]; } else sma=max(dp[v][1],sma); } dp[u][0]=ma+sma+deg[u]+1; dp[u][1]=ma+deg[u]-1; } int main(void) { int kase; read(kase); for (int i = 1; i <= kase; i++) { int n; read(n); vector<int> edge[n+1],deg(n+1); for(int u,v,i=1;i<n;++i){ read(u); read(v); edge[u].push_back(v); edge[v].push_back(u); ++deg[u]; ++deg[v]; } int dp[n+1][2]={0}; int root=1; while(root<=n&°[root]==1) ++root; if (root>n) {puts("2"); continue;} DFS(root,root,edge,deg,dp); int ans=0; for(int i=1;i<=n;++i) ans=max(ans,dp[i][0]); write(ans,'\n'); } return 0; }
G. Adilbek and the Watering System (CF 1238 G)
题目大意
浇花,水壶容量,每分钟消耗一个单位的水,要浇分钟,初始有单位的水,现有个朋友,第个朋友会在分钟来,最多带单位的水,每单位水售价。现要求能不断浇水,直到分钟。最小化花费。不可行输出。
解题思路
其实完全可以变成汽车加油问题。
只是油箱容量有限制,我们仿照汽车加油问题采取贪心策略。
由于原先的汽车加油问题中油箱没有容量限制,使得我们可以在没油的时候才决定之前该在哪个加油站加油。而这里有限制,如果仍采取上述策略的话很有可能导致某处加油会爆容量。
为了防止爆容量,我们可以在每个加油站都把油箱加满,而在使用油的时候再认为我们花费了钱去买它。当到达一个加油站时,我们对油箱里单价比当前加油站的油高的油进行替换,这样我们就时刻保证油箱里的油是可使用的最便宜的,正确性很显然的。用即可实现。表示油箱里单价为的油有单位。
神奇的代码
#include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>(b)?(a):(b)))) #define ABS(a) ((((a)>0?(a):-(a)))) using namespace std; typedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<PII> VPII; typedef vector<LL> VL; typedef pair<LL,LL> PLL; typedef vector<PLL> VPLL; template <typename T> void read(T &x) { int s = 0, c = getchar(); x = 0; while (isspace(c)) c = getchar(); if (c == 45) s = 1, c = getchar(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); if (s) x = -x; } template <typename T> void write(T x, char c = ' ') { int b[40], l = 0; if (x < 0) putchar(45), x = -x; while (x > 0) b[l++] = x % 10, x /= 10; if (!l) putchar(48); while (l) putchar(b[--l] | 48); putchar(c); } int main(void) { int kase; read(kase); for (int i = 1; i <= kase; i++) { int n,m,c,c0; read(n); read(m); read(c); read(c0); map<int,int> qwq; vector<pair<int,pair<int,int>>> f; for(int t,a,b,i=1;i<=n;++i){ read(t); read(a); read(b); f.push_back(make_pair(t,make_pair(b,a))); } f.push_back(make_pair(0,make_pair(0,c0))); f.push_back(make_pair(m,make_pair(0,0))); sort(f.begin(),f.end(),less<pair<int,pair<int,int>>>()); LL ans=0; int cur=c0; qwq[f[0].second.first]=f[0].second.second; for(int i=1;i<=n+1;++i){ if (f[i].first>m) break; int tmp=f[i].first-f[i-1].first; if (tmp>cur){ans=-1; break;} while(tmp>0){ int qaq=min(tmp,qwq.begin()->second); ans+=(LL)qaq*qwq.begin()->first; qwq.begin()->second-=qaq; if (qwq.begin()->second==0) qwq.erase(qwq.begin()); tmp-=qaq; cur-=qaq; } cur+=f[i].second.second; qwq[f[i].second.first]+=f[i].second.second; while(cur>c){ int qaq=min(cur-c,qwq.rbegin()->second); cur-=qaq; qwq.rbegin()->second-=qaq; auto it=qwq.end(); --it; if (qwq.rbegin()->second==0) qwq.erase(it); } } write(ans,'\n'); } return 0; }
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/12253208.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现