隐藏页面特效

AtCoder Regular Contest 153(持续更新)

1|0Preface


B题粗糙了改了好几个版本,最后索性从头理了一遍思路才过

然后剩下40min想C又歪了(构造题精通的被动消失了),还剩25min的时候忍不住了看LPL去了

话说现在的ARC感觉和以前的AGC难度相当啊,不过也许是没有陈指导教我我什么都做不来


2|0A - AABCDDEFE


就是用类似康托展开的思路来算每一部分的值,直接看代码吧

#include<cstdio> #include<iostream> #define RI register int #define CI const int& using namespace std; int n; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); RI i; scanf("%d",&n); --n; int p=n/100000,q=n%100000; for (i=1;i<=2;++i) putchar(p+'1'); int pp=q/1000,qq=q%1000; putchar(pp/10+'0'); putchar(pp%10+'0'); int ppp=qq/100,qqq=qq%100; for (i=1;i<=2;++i) putchar(ppp+'0'); int pppp=qqq/10,qqqq=qqq%10; putchar(pppp+'0'); putchar(qqqq+'0'); putchar(pppp+'0'); return 0; }

3|0B - Grid Rotations


话说我比赛时的做法怪的很,还找不到方法解释,结果现在写Editorial的时候就想到个很好的解释法

先讲比赛时想的,首先容易发现行和列的情况可以分别独立考虑,我们只要求出每一行在操作后变成哪一行即可,记为ri

考虑对行的某次旋转操作ai,观察到前半部分每次对换的位置的下标之和为ai+1,后半部分每次对换的下标之和为ai+1+H,这两个在模H意义下时一样的

因此对于某个行ri转变后的值就是ai+1ri在模H意义下的值,因此我们根据环的性质可以发现最后ri一定可以形成一个环的形态

当然上面的说法不是很明显,我们考虑换一种方法理解

我们考虑让第1行和第n行相连,在行之间形成一个环,同时考虑一次旋转操作不会影响每一行相邻的行是什么

举个例子,比如H=4时,原来初始时环的形态是[1,2,3,4],在进行操作ai=3后变成[3,2,1,4]

不难发现每个数相邻的两个数都没有变,变化的只是1所在的位置和与其相邻的2的方向而已

因此我们只要维护每次旋转后1的位置即可,列的情况完全相同

#include<cstdio> #include<iostream> #include<vector> #include<cctype> #define RI register int #define CI const int& using namespace std; const int N=500005; int n,m,q,a[N],b[N],h[N],w[N],d; vector <char> A[N]; inline char getch(void) { char ch; while (ch=getchar(),isspace(ch)); return ch; } inline int Nxt(int x,CI T) { x+=d; if (x<=0) x+=T; if (x>T) x-=T; return x; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); RI i,j; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) for (A[i].resize(m+1),j=1;j<=m;++j) A[i][j]=getch(); int sf_h=1,sf_w=1; for (scanf("%d",&q),i=1;i<=q;++i) { scanf("%d%d",&a[i],&b[i]); ++a[i]; ++b[i]; if ((sf_h=a[i]-sf_h)<=0) sf_h+=n; if ((sf_w=b[i]-sf_w)<=0) sf_w+=m; } d=q&1?-1:1; int ct; h[sf_h]=1; w[sf_w]=1; for (ct=1,i=Nxt(sf_h,n);i!=sf_h;i=Nxt(i,n)) h[i]=++ct; for (ct=1,i=Nxt(sf_w,m);i!=sf_w;i=Nxt(i,m)) w[i]=++ct; for (i=1;i<=n;++i,putchar('\n')) for (j=1;j<=m;++j) putchar(A[h[i]][w[j]]); return 0; }

4|0C - ± Increasing Sequence


原来是个如此simple的构造题,给我CPU干过载了

我们不妨先进行一次很naive的尝试,令xi=i,并统计出此时i=1NAixi的值sum

sum=0则显然直接输出即可,否则我们求出Ai的前缀和数组pfxi,并分类讨论:

  • sum>0,我们考虑找到第一个pfxi=1的位置pos,然后我们发现每当我们将xj,j[1,pos]1时,最后的i=1NAixi就会恰好减1,因此我们直接让xj,j[1,pos]减去sum即可
  • sum<0,类似上面的思路,我们设第一个pfx=1的位置为pos,直接让xj,j[1,pos]加上sum即可

考虑到sum的范围是n2级别的,因此可以满足|xi|1012的限制

#include<cstdio> #include<iostream> #define RI register int #define CI const int& using namespace std; const int N=200005; int n,a[N],pfx[N]; long long ans[N],sum; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); RI i,j; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&a[i]),pfx[i]=pfx[i-1]+a[i],ans[i]=i,sum+=1LL*ans[i]*a[i]; bool flag=0; if (sum==0) flag=1; else if (sum>0) { for (i=1;i<=n;++i) if (pfx[i]==1) { for (j=1;j<=i;++j) ans[j]-=sum; flag=1; break; } } else { for (i=1;i<=n;++i) if (pfx[i]==-1) { for (j=1;j<=i;++j) ans[j]+=sum; flag=1; break; } } if (flag) for (puts("Yes"),i=1;i<=n;++i) printf("%lld ",ans[i]); else puts("No"); return 0; }

5|0D - Sum of Sum of Digits


好劲的数位DP

首先一眼把每一位分开考虑贡献,我们设F(A)表示序列A的答案,Fr(A) (0r9)表示x的最后一位为r时的答案

不难发现F(A)=minrFr(A),而Fr(A)的转移就是考虑每个数最后一位的贡献,但是要注意进位问题

举个例子,设A={123,45,678,90},则有:

  • F1({123,45,678,90})=20+F({12,4,67,9})
  • F5({123,45,678,90})=16+F({12,5,68,9})

因此我们只需要枚举x的每一位,然后把贡献分开算即可,现在的问题就是怎么把进位与否这一信息压缩到DP的状态里

我们观察一下,假设现在枚举的是x的第i位,我们令bi=10iAimod10i,然后将bi从小到大排序,设x=xmod10i

可以发现,当x[0,b1)时不会产生进位,当x[b1,b2)时产生一个进位,当x[b2,b3)时产生两个进位

以此类推,当x[bn,10i)时产生了n个进位,换句话说x的不同取值实际上只是被划分成了n+1个区间,区间内的选取是等价的

因此我们不需要记录哪个数产生了进位,只要记下在做完第i位后有几个数进位即可

具体实现可以用桶记录下每一位上每种数的个数来加速转移,复杂度O(n×103)

#include<cstdio> #include<iostream> #include<algorithm> #define int long long #define RI register int #define CI const int& using namespace std; const int N=200005; int n,a[N],f[11][N],c[11],M; inline bool cmp(CI x,CI y) { return x%M>y%M; } signed main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); RI i,j,k,x; for (scanf("%lld",&n),i=1;i<=n;++i) scanf("%lld",&a[i]); for (i=0;i<11;++i) for (j=0;j<=n;++j) f[i][j]=1e18; for (f[0][0]=i=0,M=1;i<10;++i,M*=10LL) { for (sort(a+1,a+n+1,cmp),j=0;j<=10;++j) c[j]=0; for (j=1;j<=n;++j) ++c[a[j]/M%10]; for (j=0;j<=n;++j) { if (j) --c[a[j]/M%10],++c[a[j]/M%10+1]; for (x=0;x<10;++x) { int C=0,L=0; for (k=0;k<=10;++k) C+=(k+x)/10*c[k],L+=(k+x)%10*c[k]; f[i+1][C]=min(f[i+1][C],f[i][j]+L); } } } return printf("%lld",f[10][0]),0; }

__EOF__

本文作者hl666
本文链接https://www.cnblogs.com/cjjsb/p/17056375.html
关于博主:复活的ACM新生,目前爱好仅剩Gal/HBR/雀魂/单机/OSU
版权声明:转载请注明出处
声援博主:欢迎加QQ:2649020702来DD我
posted @   空気力学の詩  阅读(92)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示