隐藏页面特效

Codeforces Round 953 (Div. 2)

1|0Preface


经典30min写完前四题,然后E题大脑宕机想复杂,最后写了一坨很难调试的东西成功把自己送走

趁着 Div1 的训练还没开始赶紧找回点状态吧,不然到时候保准天天坑队友的说


2|0A. Alice and Books


不难发现 an 一定会取,那么在剩下的里面找一个最大的自成一堆就行

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; const int N=105; int t,n,a[N]; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]); printf("%d\n",*max_element(a+1,a+n)+a[n]); } return 0; }

3|0B. New Bakery


把式子写出来不难发现是个二次函数,可以直接解析求出最值,也可以直接写三分求解

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; int t,n,a,b; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { scanf("%d%d%d",&n,&a,&b); int l=0,r=min(n,b); auto calc=[&](CI k) { return 1LL*(b+b-k+1)*k/2LL+1LL*a*(n-k); }; while (r-l>2) { int lmid=l+(r-l)/3,rmid=r-(r-l)/3; if (calc(lmid)>=calc(rmid)) r=rmid; else l=lmid; } int pos=l; for (RI i=l+1;i<=r;++i) if (calc(i)>calc(pos)) pos=i; printf("%lld\n",calc(pos)); } return 0; }

4|0C. Manhattan Permutations


首先不难发现 k 是奇数一定无解,否则我们考虑在 [1,2,,n] 的基础上进行若干交换

手玩一下不难发现每次换最远的没交换过的两个可以达到理论上界,而且可以构造出任意一个中间值

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; const int N=200005; int t,n,p[N]; LL k; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { scanf("%d%lld",&n,&k); if (k%2==1) { puts("No"); continue; } RI i,j,l; for (i=1;i<=n;++i) p[i]=i; for (i=1,j=n;i<j&&k>0;++i,--j) { int tmp=(j-i)*2; if (k>=tmp) k-=tmp,swap(p[i],p[j]); else { for (l=i+1;l<=j;++l) if ((l-i)*2==k) { k=0,swap(p[i],p[l]); break; } } } if (k>0) puts("No"); else { for (puts("Yes"),i=1;i<=n;++i) printf("%d%c",p[i]," \n"[i==n]); } } return 0; }

5|0D. Elections


感觉被我写复杂了,摸了半天摸出来一坨,好在写完就过了没浪费多少时间

首先特判掉 1,n 两个人的情况,并直接把刚开始多出来的 c 个人加到 a1

对于 i[2,n1],我们先找出 mx=maxi<jnaj,随后进行讨论:

  • mx>ai,此时无论如何 [1,i1] 的人都必须被干掉,否则 ai 没法吃到闲散的票就不可能超过后面的人。算出此时 ai 的值 ai 后再进行讨论:
    • mx>ai,则需要一次操作干掉 mx 对应的人,此时局面显然满足要求
    • mxai,则不需要额外的操作
  • mxai,此时不需要考虑后面的人,考虑把所有 j[1,i1]ajai 的人都干掉,之后又会出现两种情况:
    • 干掉的人对应的闲散票加到 [1,i1] 中第一个没被干掉的人上以后得到的值 <ai,此时不用进行额外的操作
    • 干掉的人对应的闲散票加到 [1,i1] 中第一个没被干掉的人上以后得到的值 ai,此时 [1,i1] 中的所有人都必须被干掉

上述所有操作可以维护一个权值线段树解决,总复杂度 O(nlogn)

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; const int N=200005; int t,n,c,a[N],rst[N],tot,suf[N],ans[N]; LL pfx[N]; class Segment_Tree { private: int cnt[N<<2],mnp[N<<2]; LL sum[N<<2]; public: #define TN CI now=1,CI l=1,CI r=tot #define LS now<<1,l,mid #define RS now<<1|1,mid+1,r inline void build(TN) { mnp[now]=n+1; cnt[now]=sum[now]=0; if (l==r) return; int mid=l+r>>1; build(LS); build(RS); } inline void updata(CI val,CI pos,TN) { if (l==r) { ++cnt[now]; sum[now]+=rst[val]; mnp[now]=min(mnp[now],pos); return; } int mid=l+r>>1; if (val<=mid) updata(val,pos,LS); else updata(val,pos,RS); cnt[now]=cnt[now<<1]+cnt[now<<1|1]; sum[now]=sum[now<<1]+sum[now<<1|1]; mnp[now]=min(mnp[now<<1],mnp[now<<1|1]); } inline int query_cnt(CI beg,CI end,TN) { if (beg<=l&&r<=end) return cnt[now]; int mid=l+r>>1,ret=0; if (beg<=mid) ret+=query_cnt(beg,end,LS); if (end>mid) ret+=query_cnt(beg,end,RS); return ret; } inline LL query_sum(CI beg,CI end,TN) { if (beg<=l&&r<=end) return sum[now]; int mid=l+r>>1; LL ret=0; if (beg<=mid) ret+=query_sum(beg,end,LS); if (end>mid) ret+=query_sum(beg,end,RS); return ret; } inline int query_pos(CI beg,CI end,TN) { if (beg<=l&&r<=end) return mnp[now]; int mid=l+r>>1,ret=n+1; if (beg<=mid) ret=min(ret,query_pos(beg,end,LS)); if (end>mid) ret=min(ret,query_pos(beg,end,RS)); return ret; } #undef TN #undef LS #undef RS }SEG; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i; scanf("%d%d",&n,&c); tot=0; for (i=1;i<=n;++i) scanf("%d",&a[i]); for (a[1]+=c,i=1;i<=n;++i) rst[++tot]=a[i]; if (n==1) { puts("0"); continue; } for (suf[n]=a[n],i=n-1;i>=1;--i) suf[i]=max(suf[i+1],a[i]); for (i=1;i<=n;++i) pfx[i]=pfx[i-1]+a[i]; sort(rst+1,rst+tot+1); tot=unique(rst+1,rst+tot+1)-rst-1; for (i=1;i<=n;++i) a[i]=lower_bound(rst+1,rst+tot+1,a[i])-rst; if (rst[a[1]]>=suf[2]) ans[1]=0; else ans[1]=1; for (ans[n]=0,i=1;i<n;++i) if (a[i]>=a[n]) { ans[n]=n-1; break; } for (SEG.build(),SEG.updata(a[1],1),i=2;i<n;++i) { if (suf[i+1]>rst[a[i]]) { ans[i]=i-1; LL cur=rst[a[i]]+pfx[i-1]; if (cur<suf[i+1]) ++ans[i]; } else { ans[i]=SEG.query_cnt(a[i],tot); if (ans[i]<i-1&&(a[i]>1?rst[a[SEG.query_pos(1,a[i]-1)]]:0)+SEG.query_sum(a[i],tot)>=rst[a[i]]) ans[i]=i-1; } SEG.updata(a[i],i); } for (i=1;i<=n;++i) printf("%d%c",ans[i]," \n"[i==n]); } return 0; }

6|0E. Computing Machine


这题好像是个神秘的 O(n) ad hoc 题,但我完全没想到神秘奇妙性质只感觉可以莫队就直接冲了

首先不难发现先扫一遍序列 ab 尽量多的位置涂成 1;然后回头让 ba 尽量多的位置涂成 1;这个策略显然是最优的

因此我们发现加入一个位置 i 后至多影响其周围 [i3,i+3] 范围内的贡献,因此可以通过莫队来处理

但写的时候发现加入的情况还好说,删除的情况怎么写都感觉漏Case,无奈之下只好去写回滚莫队这种不用删除的科技

结构写完发现由于上面讲的一个位置的较大的影响范围,还不能像传统的回滚莫队一样直接滚回块尾后面的位置

但我最擅长的就是魔改经典算法了,后面发现我们手动放宽回滚莫队中做暴力的区间阈值,使得右端点可以推到较远的位置(代码里取了 10

然后手动把会因为左端点移动带来影响的前 3 个位置记录下来,每次回滚左端点的时候一并复原即可

总复杂度 O(mn),胜在不用动脑子找性质

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; const int N=200005; int blk[N]; struct ques { int l,r,id; friend inline bool operator < (const ques& A,const ques& B) { return blk[A.l]!=blk[B.l]?blk[A.l]<blk[B.l]:A.r<B.r; } }q[N]; int t,n,m,sz,ta[N],tb[N],ans[N]; char a[N],b[N]; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i,j; scanf("%d%s%s",&n,a+1,b+1); for (sz=(int)sqrt(n),i=1;i<=n;++i) blk[i]=(i-1)/sz+1; for (scanf("%d",&m),i=1;i<=m;++i) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i; RI l=1,r=0,p=1; sort(q+1,q+m+1); for (i=1;i<=blk[n];++i) { int ret=0,lim=min(n,i*sz); r=lim; int tmp_ta[3],tmp_tb[3]; tmp_ta[0]=-1; while (p<=m&&blk[q[p].l]==i) { auto chk=[&](int& x,CI y) { if (x==0&&y==1) ++ret; if (x==1&&y==0) --ret; x=y; }; auto addr=[&](CI r) { ta[r]=a[r]-'0'; tb[r]=b[r]-'0'; ret+=ta[r]; if (r-2>=l) { if (tb[r]&&tb[r-2]) chk(ta[r-1],1); if (a[r]=='0'&&a[r-2]=='0') tb[r-1]=1; if (r-3>=l&&tb[r-1]&&tb[r-3]) chk(ta[r-2],1); } }; auto addl=[&](CI l) { ta[l]=a[l]-'0'; tb[l]=b[l]-'0'; ret+=ta[l]; if (l+2<=r) { if (tb[l]&&tb[l+2]) chk(ta[l+1],1); if (a[l]=='0'&&a[l+2]=='0') tb[l+1]=1; if (l+3<=r&&tb[l+1]&&tb[l+3]) chk(ta[l+2],1); } }; auto BF=[&](CI l,CI r) { RI i; static int ta[N],tb[N]; for (i=l;i<=r;++i) ta[i]=a[i]-'0',tb[i]=b[i]-'0'; for (i=l;i+2<=r;++i) if (a[i]=='0'&&a[i+2]=='0') tb[i+1]=1; for (i=l;i+2<=r;++i) if (tb[i]&&tb[i+2]) ta[i+1]=1; int cur=0; for (i=l;i<=r;++i) cur+=ta[i]; return cur; }; l=lim+1; if (q[p].r-q[p].l+1<=sz+10) { ans[q[p].id]=BF(q[p].l,q[p].r); ++p; continue; } while (r<q[p].r) addr(++r); if (tmp_ta[0]==-1) { for (j=0;j<3;++j) tmp_ta[j]=ta[lim+1+j]; for (j=0;j<3;++j) tmp_tb[j]=tb[lim+1+j]; } int tmp=ret; while (l>q[p].l) addl(--l); ans[q[p++].id]=ret; ret=tmp; for (j=0;j<3;++j) ta[lim+1+j]=tmp_ta[j]; for (j=0;j<3;++j) tb[lim+1+j]=tmp_tb[j]; } } for (i=1;i<=m;++i) printf("%d\n",ans[i]); } return 0; }

7|0F. Large Graph


本来感觉没啥突破口的,后面看到 k2 就知道是个傻逼题了

因为此时所有不为 1 的主对角线会直接连通在一起,因此原问题就转化为 2n1 条主对角线直接的连通性问题了

同时主对角线还有个很好的性质,就是我们从左到右对其编号后,则编号为 i 和编号为 j 的两条对角线中任意选出两个元素,它们的曼哈顿距离都为 |ij|

利用上面两个性质二维的问题就变成一维的情况了,看到 gcd 就考虑分解质因数

对于某个质数 p,不妨设其倍数对应的下标构成集合 posp,则我们将 posp 中的元素排序后每次判断相邻的两个元素能否连边即可

用并查集暴力维护连通块,总复杂度 O(nlogn×α(n))

#include<cstdio> #include<iostream> #include<utility> #include<vector> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #include<set> #include<array> #include<random> #include<bitset> #include<ctime> #include<limits.h> #include<assert.h> #include<unordered_set> #include<unordered_map> #define RI register int #define CI const int& #define mp make_pair #define fi first #define se second #define Tp template <typename T> using namespace std; typedef long long LL; typedef long double LDB; typedef unsigned long long u64; typedef pair <int,int> pi; typedef vector <int> VI; typedef array <int,3> tri; const int N=2e6+5; int t,n,k,a[N],pri[N],cnt,mnp[N],fa[N]; bool vis[N]; vector <int> pos[N]; inline void init(CI n) { for (RI i=2,j;i<=n;++i) { if (!vis[i]) pri[++cnt]=i,mnp[i]=i; for (j=1;j<=cnt&&i*pri[j]<=n;++j) { vis[i*pri[j]]=1; mnp[i*pri[j]]=pri[j]; if (i%pri[j]==0) break; } } } inline int getfa(CI x) { return fa[x]!=x?fa[x]=getfa(fa[x]):x; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t),init(1e6);t;--t) { RI i; for (scanf("%d%d",&n,&k),i=1;i<=n;++i) scanf("%d",&a[n-1+i]); for (i=1;i<n;++i) a[i]=a[i+n]; vector <int> vec; for (i=1;i<=2*n-1;++i) { fa[i]=i; int x=a[i]; while (x>1) { int p=mnp[x]; pos[p].push_back(i); vec.push_back(p); while (x%p==0) x/=p; } } sort(vec.begin(),vec.end()); vec.erase(unique(vec.begin(),vec.end()),vec.end()); for (auto p:vec) { for (i=0;i<pos[p].size()-1;++i) if (pos[p][i+1]-pos[p][i]<=k) fa[getfa(pos[p][i+1])]=getfa(pos[p][i]); pos[p].clear(); } LL ans=0; for (i=1;i<=2*n-1;++i) { if (getfa(i)==i) ++ans; if (a[i]==1) ans+=(i<=n?i:2*n-i)-1; } printf("%lld\n",ans); } return 0; }

8|0Postscript


因为昨天这场E题写的很唐再加上这两天在帮徐神写字符串的题面,因此今天就只能补个博客没时间新开一场VP了,明天继续坚持开一场吧


__EOF__

本文作者hl666
本文链接https://www.cnblogs.com/cjjsb/p/18284556.html
关于博主:复活的ACM新生,目前爱好仅剩Gal/HBR/雀魂/单机/OSU
版权声明:转载请注明出处
声援博主:欢迎加QQ:2649020702来DD我
posted @   空気力学の詩  阅读(69)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
历史上的今天:
2023-07-04 AtCoder Regular Contest 163
2019-07-04 2019绍一集训
点击右上角即可分享
微信分享提示