Codeforces Round #612 (Div. 2)
A. Angry Students (CF 1287 A)
题目大意
给定一个包含和字符串,对于每一个的位置,如果它右边字母是,那么下一秒它会变成,最后一个字母如果是,则没什么事发生。问最后一次产生字母变化的时间是何时。
解题思路
找到最大的两个的间隔即是答案。
(一开始考虑最后一个A距离右端点的距离然后WA心态全崩)
神奇的代码
#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; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int kase; cin>>kase; for (int i = 1; i <= kase; i++) { int n; cin>>n; string s; cin>>s; int ans=0; int cnt=0; bool qwq=true; for(int i=0;i<n;++i){ if (s[i]=='P') ++cnt; else { if (qwq) {qwq=false;cnt=0;} else{ ans=MAX(ans,cnt); cnt=0; } } } ans=MAX(ans,cnt); if (qwq) ans=0; cout<<ans<<endl; } return 0; }
B. Hyperset (CF 1287 B)
题目大意
张卡片,有个属性,每个属性的取值为、、中的一种。现在要选取三张卡片,对于卡片的所有的每个属性,如果三张卡片是全部相同或者全部不同,这三张卡片就可以形成一个集合。问这些卡片能形成多少个集合。
解题思路
注意到,如果我们枚举了两张卡片,那么第三张卡片其实是已经确定的,我们只要判断这张卡片是否存在即可,丢到里即可。注意不要重复,我们假设三张卡片的顺序即可。
但是关于的赋值,一开始写结果了,改成或就了。看来要少用这种形式。
改成恰好过了,而在过了。所以无关顺序的话我们还是尽量用的。
其实也可以建一棵树去判断是否存在。
神奇的代码
#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; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int n,m; cin>>n>>m; unordered_map<string,int> qwq; qwq.clear(); string s[n+1]; for(int i=0;i<n;++i){ cin>>s[i]; qwq[s[i]]=i+1; } int ans=0; for(int i=0;i<n-2;++i) for(int j=i+1;j<n-1;++j){ string ss; for(int k=0;k<m;++k){ if (s[i][k]==s[j][k]) ss+=s[i][k]; else if (s[i][k]!='S'&&s[j][k]!='S') ss+='S'; else if (s[i][k]!='T'&&s[j][k]!='T') ss+='T'; else if (s[i][k]!='E'&&s[j][k]!='E') ss+='E'; } if (qwq[ss]>j) ++ans; } cout<<ans<<endl; return 0; }
C. Garland (CF 1287 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); } const int N=105; int n,dp[N][N][N][2],a[N]; int work(int pos,int zero,int one,int parity){ if (zero<0||one<0) return 1e9+7; if (pos==n) return 0; if (dp[pos][zero][one][parity]!=-1) return dp[pos][zero][one][parity]; if (a[pos]!=0) return dp[pos][zero][one][parity]=work(pos+1,zero,one,a[pos]&1)+((a[pos]&1)^parity); return dp[pos][zero][one][parity]=min(work(pos+1,zero-1,one,0)+(parity==1),work(pos+1,zero,one-1,1)+(parity==0)); } int main(){ freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); read(n); int cnt[2]; cnt[0]=n/2; cnt[1]=n-cnt[0]; for(int i=0;i<n;++i){ read(a[i]); if (a[i]!=0) --cnt[a[i]&1]; } memset(dp,-1,sizeof(dp)); printf("%d\n",min(work(0,cnt[0],cnt[1],0),work(0,cnt[0],cnt[1],1))); return 0; } /* int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); int n; cin>>n; vector<int> qwq(n); for(int i=0;i<n;++i) cin>>qwq[i]; int cnt0=n/2,cnt1=n-cnt0; for(int i:qwq){ if (i==0) continue; else if (i&1) --cnt1; else --cnt0; } vector<pair<int,int>> qaq[2]; int l=-1,r=0,ans=0; while(r<n){ while(l<n&&qwq[l+1]!=0) ++l; if (l>=n) break; r=l+1; while(r<n&&qwq[r]==0) ++r; if (r==n) if (l==-1) {ans=-1; break;} else qaq[qwq[l]&1].push_back(make_pair(r-l-1,1)); else { if (l==-1) qaq[qwq[r]&1].push_back(make_pair(r-l-1,1)); else if ((qwq[l]&1)^(qwq[r]&1)) ++ans; else qaq[qwq[l]&1].push_back(make_pair(r-l-1,2)); } l=r; } if (ans==-1) if (n==1) cout<<"0"<<endl; else cout<<"1"<<endl; else{ vector<int> dp0(cnt0+2),dp1(cnt1+2); for(auto i:qaq[0]) for(int j=cnt0;j>=i.first;--j) dp0[j]=MAX(dp0[j],dp0[j-i.first]+i.second); for(auto i:qaq[1]) for(int j=cnt1;j>=i.first;--j) dp1[j]=MAX(dp1[j],dp1[j-i.first]+i.second); int su0=0,su1=0; for(auto i:qaq[0]) su0+=i.second; for(auto i:qaq[1]) su1+=i.second; int ma0=0,ma1=0; for(auto i:dp0) ma0=MAX(ma0,i); for(auto i:dp1) ma1=MAX(ma1,i); ans+=su0-ma0+su1-ma1; for(int i=1;i<n;++i){ if (qwq[i]!=0&&qwq[i-1]!=0) if ((qwq[i]&1)^(qwq[i-1]&1)) ++ans; } cout<<ans<<endl; } return 0; } */
D. Numbers on Tree (CF 1287 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); } const int N=2003; int n,root; vector<int> son[N],ji; int q[N],ans[N]; int DFS(int u){ int cnt=0; for(int i:son[u]) cnt+=DFS(i); if (u==0) return 0; if (q[u]>cnt) {puts("NO"); exit(0);} ji.insert(ji.begin()+q[u],u); return cnt+1; } int main(void) { freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); read(n); for(int f,i=1;i<=n;++i){ read(f); read(q[i]); son[f].push_back(i); } DFS(0); int qwq=0; for(int i:ji) ans[i]=++qwq; puts("YES"); for(int i=1;i<=n;++i) printf("%d%c",ans[i],i==n?'\n':' '); return 0; }
考试周打CF无所畏惧
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/12158322.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步