很久没rated打过cf的比赛了,这次打得还行,至少进前100了

点我看题

A. Glory Addicts

把类型0的数放进数组a里,类型1的数放进数组b里。如果\(|a|=|b|\),你可以把所有数里最小的放在第一个,其他的交错排列,这样除了最小的其他都能取到2的系数。这个需要特判。否则假设\(|a|>|b|\),则可以把a中最小的放第一个,然后分别把b和a中最大的\(|b|\)个拿出来交替排列,这样能使b和a中最大的\(|b|\)个都取到2的系数。容易发现没有更好的排法了。

时间复杂度\(O(nlogn)\)。

点击查看代码
  1. #include <bits/stdc++.h>
  2. #define rep(i,n) for(int i=0;i<n;++i)
  3. #define repn(i,n) for(int i=1;i<=n;++i)
  4. #define LL long long
  5. #define pii pair <int,int>
  6. #define fi first
  7. #define se second
  8. #define mpr make_pair
  9. #define pb push_back
  10. using namespace std;
  11. LL t,n,tt[100010],vv[100010];
  12. vector <LL> a,b;
  13. int main()
  14. {
  15. cin>>t;
  16. rep(tn,t)
  17. {
  18. scanf("%lld",&n);
  19. a.clear();b.clear();
  20. rep(i,n) scanf("%lld",&tt[i]);
  21. rep(i,n) scanf("%lld",&vv[i]);
  22. LL ans=0;
  23. LL mn=1e18;
  24. rep(i,n)
  25. {
  26. if(tt[i]==0) a.pb(vv[i]);else b.pb(vv[i]);
  27. ans+=vv[i];
  28. mn=min(mn,vv[i]);
  29. }
  30. sort(a.begin(),a.end());reverse(a.begin(),a.end());
  31. sort(b.begin(),b.end());reverse(b.begin(),b.end());
  32. if(a.size()==b.size())
  33. {
  34. printf("%lld\n",ans*2-mn);
  35. continue;
  36. }
  37. LL sz=min(a.size(),b.size()),v1=0,v2=0;
  38. rep(i,sz) v1+=a[i];rep(i,sz) v1+=b[i];
  39. ans+=v1;
  40. printf("%lld\n",ans);
  41. }
  42. return 0;
  43. }

B. Prefix Sum Addicts

应该是比较容易错的题吧,我最后几分钟想着来不及做G了就去叉这题,结果叉了两个都失败了,喜提-100pts

首先k=1的时候一定是YES。否则a数组最后的k-1项已经确定了,先看已经确定的有没有违反不降。令a的第\(n-k+2\)项为x(已经确定了)。则它前面的数最大只能都是x。所以就看\(x \cdot (n-k+1)\)是否\(\geq s_{n-k+1}\)就行了。最后就是注意要开long long。

时间复杂度\(O(n)\)。

点击查看代码
  1. #include <bits/stdc++.h>
  2. #define rep(i,n) for(int i=0;i<n;++i)
  3. #define repn(i,n) for(int i=1;i<=n;++i)
  4. #define LL long long
  5. #define pii pair <int,int>
  6. #define fi first
  7. #define se second
  8. #define mpr make_pair
  9. #define pb push_back
  10. using namespace std;
  11. LL t,n,k,s[100010];
  12. int main()
  13. {
  14. cin>>t;
  15. rep(tn,t)
  16. {
  17. scanf("%lld%lld",&n,&k);
  18. for(int i=n-k+1;i<=n;++i) scanf("%lld",&s[i]);
  19. LL lst=1e12,ok=1;
  20. for(int i=n-1;i>=n-k+1;--i)
  21. {
  22. LL cur=s[i+1]-s[i];
  23. if(cur>lst)
  24. {
  25. ok=0;
  26. break;
  27. }
  28. lst=cur;
  29. }
  30. LL can=(n-k+1)*lst;
  31. if(can<s[n-k+1]) ok=0;
  32. puts(ok==1 ? "YES":"NO");
  33. }
  34. return 0;
  35. }

C. Even Number Addicts

一开始以为是要观察什么神奇的性质,结果一看数据范围哦豁\(n\leq 100\),那不是直接暴力算就行嘛

Alice想要尽量取到偶数个奇数,Bob想要尽量让Alice取到奇数个奇数。\(dp_{player,val,o,e}\)表示当前玩家是player(值为0/1 表示Alice/Bob),当前Alice取到的奇数个数奇偶性为val,还剩o个奇数没取,e个偶数没取,此时的先手能不能胜利。转移也是很简单的,枚举接下来取奇数还是偶数就行。如果能转移到的状态有任意一个是必败,那当前状态就是必胜;否则当前状态为必败。边界情况就是\(o=e=0\),根据player和val的值确定胜败即可。可以在所有询问之前先\(O(100^2)\)把dp的表打出来。

时间复杂度\(O(100^2)\)。

点击查看代码
  1. #include <bits/stdc++.h>
  2. #define rep(i,n) for(int i=0;i<n;++i)
  3. #define repn(i,n) for(int i=1;i<=n;++i)
  4. #define LL long long
  5. #define pii pair <int,int>
  6. #define fi first
  7. #define se second
  8. #define mpr make_pair
  9. #define pb push_back
  10. using namespace std;
  11. int t,n,a[110],dp[2][2][110][110];
  12. int dfs(int p,int v,int o,int e)
  13. {
  14. int &ret=dp[p][v][o][e];
  15. if(ret!=-1) return ret;
  16. if(o==0&&e==0)
  17. {
  18. if(p==0) return ret=(v==0 ? 1:0);
  19. return ret=(v==1 ? 1:0);
  20. }
  21. ret=0;
  22. if(p==0)
  23. {
  24. if(o>0) ret|=(dfs(1,v^1,o-1,e)==0);
  25. if(e>0) ret|=(dfs(1,v,o,e-1)==0);
  26. }
  27. else
  28. {
  29. if(o>0) ret|=(dfs(0,v,o-1,e)==0);
  30. if(e>0) ret|=(dfs(0,v,o,e-1)==0);
  31. }
  32. return ret;
  33. }
  34. int main()
  35. {
  36. rep(i,2) rep(ii,2) rep(j,105) rep(k,105) dp[i][ii][j][k]=-1;
  37. rep(i,2) rep(ii,2) rep(j,103) rep(k,103) if(dp[i][ii][j][k]==-1) dfs(i,ii,j,k);
  38. cin>>t;
  39. rep(tn,t)
  40. {
  41. cin>>n;
  42. int o=0,e=0;
  43. rep(i,n)
  44. {
  45. scanf("%d",&a[i]);
  46. if(abs(a[i])%2!=0) ++o;
  47. else ++e;
  48. }
  49. puts(dp[0][0][o][e]==1 ? "Alice":"Bob");
  50. }
  51. return 0;
  52. }

D. Permutation Addicts

把数值分成2类,\(\leq k\)的和\(>k\)的。观察题目中的定义可知,\(b_i\)的含义是:在a序列中,从为i的元素往前找,第一个与i不同类的元素的。最终的a序列是会被划分成若干块的,每一块内的元素类型都相同,且相邻两个块内的元素类型不同。发现\(b_i=0或n+1\),当且仅当i在第一块内。所以我们可以快速地找出第一块内的所有元素(通过检查\(b_i\))。但是每一块内的所有元素顺序也不能乱排,其实每一块内有且仅有1个元素x,满足存在若干y使得\(b_y=x\)(最后一块除外),这也是容易看出的(回顾\(b_i\)的含义)。这个x必须排在当前块的最后一个,而块内其他元素可以按任意顺序排。同时发现,所有满足\(b_y=x\)的y就是下一块的所有元素。到这里这题就做完了,按照上面说的模拟即可。

时间复杂度\(O(n)\)。

点击查看代码
  1. #include <bits/stdc++.h>
  2. #define rep(i,n) for(int i=0;i<n;++i)
  3. #define repn(i,n) for(int i=1;i<=n;++i)
  4. #define LL long long
  5. #define pii pair <int,int>
  6. #define fi first
  7. #define se second
  8. #define mpr make_pair
  9. #define pb push_back
  10. using namespace std;
  11. int t,n,b[100010],k,ans[100010];
  12. vector <int> v[100010];
  13. int main()
  14. {
  15. cin>>t;
  16. rep(tn,t)
  17. {
  18. scanf("%d",&n);
  19. rep(i,n+3) v[i].clear();
  20. repn(i,n)
  21. {
  22. scanf("%d",&b[i]);
  23. v[b[i]].pb(i);
  24. }
  25. int curnode,startpos=1,stat;
  26. if(v[0].size()>0) curnode=0,stat=1;
  27. else curnode=n+1,stat=0;
  28. k=0;
  29. while(startpos<=n)
  30. {
  31. int nxt=-1;vector <int> tmp;
  32. rep(i,v[curnode].size())
  33. {
  34. int u=v[curnode][i];
  35. if(v[u].size()>0) nxt=u;
  36. else tmp.pb(u);
  37. }
  38. rep(i,tmp.size()) ans[startpos+i]=tmp[i];
  39. ans[startpos+tmp.size()]=nxt;
  40. if(stat==0) k+=v[curnode].size();
  41. startpos+=v[curnode].size();
  42. curnode=nxt;
  43. stat^=1;
  44. }
  45. printf("%d\n",k);
  46. repn(i,n) printf("%d ",ans[i]);
  47. puts("");
  48. }
  49. return 0;
  50. }

E. Balance Addicts

似乎有很多群友写的很烦还被卡,我的做法还是比较好写的。

原数组下标从1开始。题目中的划分序列,其实等价于:

  • 选出2个序列x、y(下标从1开始),长度都为k(\(k>0\)),满足x严格递增,y严格递减,x和y中的所有元素都在[1,n]中
  • 并且满足\(x_k<y_k\)
  • 那么我们就可以把\([1,x_1]和[y_1,n]\)各缩成一个数并匹配;\([x_1+1,x_2]和[y_2,y_1-1]\)各缩成一个数并匹配\(\cdots\)\([x_{k-1}+1,x_k]和[y_k,y_{k-1}-1]\)各缩成一个数并匹配。这里还要要求每两个匹配区间内的数之和相等。
  • \(x_k和y_k\)之间如果还有空隙,把中间的数缩成一个,作为回文序列的最中间一个数。

发现每一对合法的(x,y)都对应了一种划分序列的方案。还要加上整个序列合并成一个数的1种方案。

可以令\(dp_{i,j}\)表示当前已经选择了x和y的一段长度都为p的前缀,其中\(x_p=i,y_p=j\)的方案数。如果p=0则用\(dp_{0,n+1}\)表示。发现每个\(dp_{i,j}\)可以从某些满足条件的\(dp_{i',j'}(i'<i,j'>j)\)转移。但是有这些还是没法写这题的

处理出原序列的前缀和和后缀和。发现对于每一对合法的(x,y)和任意i,都满足\(x_i\)位置的前缀和=\(y_i\)位置的后缀和。因此可以按照值从小到大,枚举每一段极长连续且相等的前缀和,令其范围为[l,r],前缀和值为val。显然,\(a_l \neq 0\),区间内其他位置都满足\(a_i=0\)。如果没有任何一个位置满足其后缀和为val,则跳过这个区间。否则,令值为val的极长后缀和区间为[l',r']。如果[l,r]和[l',r']不相交,我们可以在这两个区间内分别选择相同数量的位置,并分别接在之前提到的x序列和y序列的最后。可以记录一个变量pre,表示满足x序列的最后一个数<l,且y的最后一个数>r'的(x,y)的数量。令在[l,r]和[l',r']内选择>0个数的方案数为wys,每次令\(pre+=pre \cdot wys\)即可。如果[l,r]和[l',r']相交,那么肯定满足l'=l+1,r'=r+1,我们在[l,r']中选择偶数个位置即可。并且我们就不能再接着枚举前缀和的值了,因为我们对(x,y)的要求是x的最后一个数 < y的最后一个数。此时需要break。

时间复杂度\(O(n)\)。题解看着长但是代码好写。

点击查看代码
  1. #include <bits/stdc++.h>
  2. #define rep(i,n) for(int i=0;i<n;++i)
  3. #define repn(i,n) for(int i=1;i<=n;++i)
  4. #define LL long long
  5. #define pii pair <int,int>
  6. #define fi first
  7. #define se second
  8. #define mpr make_pair
  9. #define pb push_back
  10. using namespace std;
  11. const LL MOD=998244353;
  12. LL qpow(LL x,LL a)
  13. {
  14. LL res=x,ret=1;
  15. while(a>0)
  16. {
  17. if((a&1)==1) ret=ret*res%MOD;
  18. a>>=1;
  19. res=res*res%MOD;
  20. }
  21. return ret;
  22. }
  23. LL t,n,a[100010],pref[100010],suf[100010],fac[100010],inv[100010];
  24. vector <pair <LL,pii> > v;
  25. map <LL,pii> mp;
  26. LL C(LL nn,LL mm){return fac[nn]*inv[mm]%MOD*inv[nn-mm]%MOD;}
  27. int main()
  28. {
  29. fac[0]=1;repn(i,100005) fac[i]=fac[i-1]*i%MOD;
  30. rep(i,100003) inv[i]=qpow(fac[i],MOD-2);
  31. cin>>t;
  32. rep(tn,t)
  33. {
  34. scanf("%lld",&n);
  35. repn(i,n)
  36. {
  37. scanf("%lld",&a[i]);
  38. pref[i]=pref[i-1]+a[i];
  39. }
  40. suf[n+1]=0;
  41. for(int i=n;i>0;--i) suf[i]=suf[i+1]+a[i];
  42. v.clear();
  43. repn(i,n)
  44. {
  45. int p=i;
  46. while(p+1<=n&&pref[p+1]==pref[i]) ++p;
  47. v.pb(mpr(pref[i],mpr(i,p)));
  48. i=p;
  49. }
  50. mp.clear();
  51. for(int i=n;i>0;--i)
  52. {
  53. int p=i;
  54. while(p-1>0&&suf[p-1]==suf[i]) --p;
  55. mp[suf[i]]=mpr(p,i);
  56. i=p;
  57. }
  58. LL pre=1;
  59. rep(i,v.size()) if(mp.find(v[i].fi)!=mp.end())
  60. {
  61. LL l1=v[i].se.fi,r1=v[i].se.se,l2=mp[v[i].fi].fi,r2=mp[v[i].fi].se;
  62. if(r1<l2)
  63. {
  64. LL tot=0;
  65. repn(cho,min(r1-l1+1,r2-l2+1)) (tot+=C(r1-l1+1,cho)*C(r2-l2+1,cho))%=MOD;
  66. (pre+=tot*pre)%=MOD;
  67. }
  68. else
  69. {
  70. LL tot=0;
  71. repn(cho,(r2-l1+1)/2) (tot+=C(r2-l1+1,cho+cho))%=MOD;
  72. (pre+=tot*pre)%=MOD;
  73. break;
  74. }
  75. }
  76. printf("%lld\n",pre);
  77. }
  78. return 0;
  79. }

F. Connectivity Addicts

稍微有点诈骗。

我们染色的要求是,同种颜色必须连通,每种颜色都满足度数之和\(\leq\)点数的平方。这启发我们可以拿出度数最大的点(注意度数序列是题目初始时输入的),直接询问出所有与他相连的点,并把这些所有点都染成同一种颜色。此时被染成这种颜色的点集大小已经超过了其中点的度数的最大值,所以就算我们不断向点集中加入到原来点集中的点有边的其他点(不管加多少都行),点集仍然满足度数之和\(\leq\)点数的平方(称其为万能点集,每个万能点集中的点颜色都相同)。把度数最大的点和他所连接的点都染色后,我们再拿出没被染色的点中度数最大的,令其为点x。仍然是询问出所有与x连接的点,如果所有这些点都没被染色,那么恭喜,你又找到一个"万能点集",可以把其中的点再都染成同一种颜色,以后也可以再向其中加点。如果询问过程中发现有一个连到的点y已经被染色,那么干脆把x,以及在询问y之前询问到的所有点(都是没染色的),都加到y所属的万能点集中(可以用并查集),与y染成同一种颜色。容易发现这是符合题目中的染色规则的。重复找出度数最大的未染色点并询问的这种操作,直到没有未染色点。我们每询问一次,都有至少1个点被染色。所以总询问次数不会超过n。

时间复杂度\(O(nlogn)\)。

点击查看代码
  1. #include <bits/stdc++.h>
  2. #define rep(i,n) for(int i=0;i<n;++i)
  3. #define repn(i,n) for(int i=1;i<=n;++i)
  4. #define LL long long
  5. #define pii pair <int,int>
  6. #define fi first
  7. #define se second
  8. #define mpr make_pair
  9. #define pb push_back
  10. using namespace std;
  11. int t,n,d[1010],fa[1010],c[10010];
  12. bool con[1010];
  13. set <pii> st;
  14. int qry(int u)
  15. {
  16. cout<<"? "<<u<<endl;
  17. cout.flush();
  18. int x;cin>>x;return x;
  19. }
  20. int Find(int x)
  21. {
  22. if(fa[x]!=x) fa[x]=Find(fa[x]);
  23. return fa[x];
  24. }
  25. int main()
  26. {
  27. ios::sync_with_stdio(false);
  28. cin.tie(0);cout.tie(0);
  29. cin>>t;
  30. rep(tn,t)
  31. {
  32. cin>>n;
  33. repn(i,n) cin>>d[i];
  34. repn(i,n) fa[i]=i,con[i]=0;
  35. st.clear();
  36. repn(i,n) st.insert(mpr(-d[i],i));
  37. LL cnt=0;
  38. while(cnt<n)
  39. {
  40. pii bg=*st.begin();st.erase(st.begin());
  41. bg.fi=-bg.fi;
  42. con[bg.se]=true;
  43. ++cnt;
  44. rep(i,bg.fi)
  45. {
  46. int v=qry(bg.se);
  47. if(con[v])
  48. {
  49. fa[Find(bg.se)]=Find(v);
  50. break;
  51. }
  52. con[v]=true;fa[Find(v)]=Find(bg.se);
  53. st.erase(mpr(-d[v],v));
  54. ++cnt;
  55. }
  56. }
  57. cout<<"! ";
  58. int len=0;
  59. repn(i,n) if(Find(i)==i) c[i]=++len;
  60. repn(i,n) if(Find(i)!=i) c[i]=c[Find(i)];
  61. repn(i,n) cout<<c[i]<<' ';cout<<endl;
  62. cout.flush();
  63. }
  64. return 0;
  65. }

有一说一,H不仅有原题而且据说还是板子。。。有群友半小时不到就切了/fad

LOJ原题链接

原题是这题的强化版?

[题解] Codeforces Global Round 22 1738 A B C D E F 题解的更多相关文章

  1. Codeforces Global Round 2 题解

    Codeforces Global Round 2 题目链接:https://codeforces.com/contest/1119 A. Ilya and a Colorful Walk 题意: 给 ...

  2. Codeforces Global Round 1 (A-E题解)

    Codeforces Global Round 1 题目链接:https://codeforces.com/contest/1110 A. Parity 题意: 给出{ak},b,k,判断a1*b^( ...

  3. Codeforces Global Round 11 个人题解(B题)

    Codeforces Global Round 11 1427A. Avoiding Zero 题目链接:click here 待补 1427B. Chess Cheater 题目链接:click h ...

  4. CodeForces Global Round 1

    CodeForces Global Round 1 CF新的比赛呢(虽然没啥区别)!这种报名的人多的比赛涨分是真的快.... 所以就写下题解吧. A. Parity 太简单了,随便模拟一下就完了. B ...

  5. Codeforces Global Round 1 - D. Jongmah(动态规划)

    Problem   Codeforces Global Round 1 - D. Jongmah Time Limit: 3000 mSec Problem Description Input Out ...

  6. Codeforces Global Round 1 (CF1110) (未完结,只有 A-F)

    Codeforces Global Round 1 (CF1110) 继续补题.因为看见同学打了这场,而且涨分还不错,所以觉得这套题目可能会比较有意思. 因为下午要开学了,所以恐怕暂时不能把这套题目补 ...

  7. Codeforces Beta Round #22 (Div. 2 Only)

    Codeforces Beta Round #22 (Div. 2 Only) http://codeforces.com/contest/22 A 水题 #include<bits/stdc+ ...

  8. 暴力/DP Codeforces Beta Round #22 (Div. 2 Only) B. Bargaining Table

    题目传送门 /* 题意:求最大矩形(全0)的面积 暴力/dp:每对一个0查看它左下的最大矩形面积,更新ans 注意:是字符串,没用空格,好事多磨,WA了多少次才发现:( 详细解释:http://www ...

  9. Codeforces Global Round 3

    Codeforces Global Round 3 A. Another One Bites The Dust 有若干个a,有若干个b,有若干个ab.你现在要把这些串拼成一个串,使得任意两个相邻的位置 ...

随机推荐

  1. 论文解读(GSAT)《Interpretable and Generalizable Graph Learning via Stochastic Attention Mechanism》

    论文信息 论文标题:Interpretable and Generalizable Graph Learning via Stochastic Attention Mechanism论文作者:Siqi ...

  2. Java8新特性: CompletableFuture详解

    CompletableFuture实现了CompletionStage接口和Future接口,前者是对后者的一个扩展,增加了异步回调.流式处理.多个Future组合处理的能力,使Java在处理多任务的 ...

  3. EB和Varuxn的单字聊天

    持续更新! 本文已经征得\(Varuxn\)同意,仅当做记录网课的趣事和"深厚"的友情 原标题<ErB和Varuxn的单字聊天> 原标题来源: 这个想法来源是 \(Va ...

  4. 优雅退出在Golang中的实现

    背景 为什么需要优雅关停 在Linux下运行我们的go程序,通常有这样2种方式: 前台启动.打开终端,在终端中直接启动某个进程,此时终端被阻塞,按CTRL+C退出程序,可以输入其他命令,关闭终端后程序 ...

  5. 主流前沿的开源监控和报警系统Prometheus+Grafana入门之旅

    Prometheus概述 定义 Prometheus 官网地址 https://prometheus.io/ Prometheus 官网文档地址 https://prometheus.io/docs/ ...

  6. Luogu5367 【模板】康托展开 (康拓展开)

    \(n^2\)暴力 #include <iostream> #include <cstdio> #include <cstring> #include <al ...

  7. Docker 12 数据卷

    参考源 https://www.bilibili.com/video/BV1og4y1q7M4?spm_id_from=333.999.0.0 https://www.bilibili.com/vid ...

  8. 前端 | HTML5基础知识

    1 HTML定义 HTML(英文Hyper Text Markup Language的缩写)中文译为"超文本标签语言",主要是通过HTML标签对网页中的文本.图片.声音等内容进行描 ...

  9. ACM模式细节

    牛客网的ACM模式需要自己写输入输出,在这里简单记录一下: 基本答题框架: import java.util.*; public class Main{ public static void main ...

  10. Excel 运算符(二):比较运算符

    比较运算符用于对两个数据进行比较运算,其结果为 TRUE(真)或 FALSE(假). 运算符 含义 实例 结果 = 等于 =2=3 FALSE < 小于 =5<2 FALSE > 大 ...