隐藏页面特效

Codeforces Round #833 (Div. 2)

1|0Preface


我是大FW,B因为本地调试的时候把数组大小改成200忘记该回去了浪费了很多时间和罚时

C刚开始也没想清楚WA了两发心态爆炸,然后D其实想出了一种做法但是心态崩了就没写了

又是掉分我感觉有点难顶


2|0A. The Ultimate Square


一个SB题给我做的巨蠢,直接输出n2即可,但是我写的是个什么鬼我也不知道

#include<cstdio> #include<cmath> #define RI register int #define CI const int& using namespace std; const int N=10005; int t,n; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) scanf("%d",&n),printf("%d\n",(int)sqrt(1LL*n/2*(n/2+1)+(n&1?n+1>>1:0))); return 0; }

3|0B. Diverse Substrings


因为数的种类只有10种,根据抽屉原理,一个区间的长度最多为100,因此直接暴力做即可

#include<cstdio> #include<iostream> #define RI register int #define CI const int& using namespace std; const int N=100005; int t,n,c[10],ans; char s[N]; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i,j; for (scanf("%d%s",&n,s+1),ans=0,i=1;i<=n;++i) { for (j=0;j<10;++j) c[j]=0; int num=0,mx=0; for (j=i;j<=n;++j) { if (!c[s[j]-'0']) ++num; if (++c[s[j]-'0']>mx) mx=c[s[j]-'0']; if (mx<=num) ++ans; else if (mx>10) break; } } printf("%d\n",ans); } return 0; }

4|0C. Zero-Sum Prefixes


首先求出原序列的前缀和pfx,考虑被0分开的每段区间,不难发现这个区间前面的0改成这个区间里出现次数最多的pfx即可

但是要注意开头的那个前面没有0的区间的情况要特别考虑,以及最后留下的一个单独的0结尾的情况

#include<cstdio> #include<map> #include<iostream> #define RI register int #define CI const int& using namespace std; int t,n,x,ans; map <long long,int> c; inline void calc(int mx=0) { for (auto v:c) mx=max(mx,(v.first?0:1)+v.second); ans+=mx; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i; long long pfx=0,lst=0; bool flag=0; for (scanf("%d",&n),ans=0,i=1;i<=n;++i) { scanf("%d",&x); if (!x) calc(),c.clear(),c[0]=pfx=0,flag=1; else { if (!flag) { if (pfx+=x,!pfx) ++ans; } else ++c[pfx+=x]; } } calc(); printf("%d\n",ans); c.clear(); } return 0; }

5|0D. ConstructOR


比赛的时候想了个算法以为是假的就没写,后来发现是对的(虽然我不会证正确性)

就是先考虑x的后30位,我们令x=a|b,这样两个数的限制就变成一个了,记y=a|bmodd

接下来考虑前30位,相当于解方程230×x=dy(modd),直接上扩欧即可,代码我没写

考虑一种科学的做法,我们发现若a,b中有一个为奇数,而d为偶数时显然是无解的

否则说明a,b,d最低位都是0,原问题转化为a2,b2,d2之间的问题

因此我们设LSB(x)表示x的二进制表示中最低位的1出现的位置,则min(LSB(a),LSB(b))<LSB(d)时无解

考虑有解的情况,我们从低到高考虑每一个x0d1的位,把答案加上d×2k即可(k为当前位与LSB(d)的差值)

#include<cstdio> #define int long long #define RI register int #define CI const int& using namespace std; int t,a,b,d; signed main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%lld",&t);t;--t) { RI i; bool flag=1; int lsb; for (scanf("%lld%lld%lld",&a,&b,&d),i=0;i<30;++i) { if ((d>>i)&1) { lsb=i; break; } if (((a|b)>>i)&1) { flag=0; break; } } if (!flag) { puts("-1"); continue; } int ans=0; for (i=lsb;i<30;++i) if ((((a|b)>>i)&1)&&!((ans>>i)&1)) ans+=d<<(i-lsb); printf("%lld\n",ans); } return 0; }

6|0E. Yet Another Array Counting Problem


论你能不能想到笛卡尔树

今天补题的时候刚打开Tutorial结果看到笛卡尔树就知道怎么做了

原来的题目要求就是a,b的笛卡尔树同构,直接来个DP,设fi,j表示树上点i的权值为j时的方案数

转移的话设gi,j=kjfi,k,则fi,j=glsoni,j1×grsoni,j,注意左子树因为出现在i前面因此不能等于i,而右子树就可以等于

#include<cstdio> #include<vector> #define RI register int #define CI const int& using namespace std; const int N=200005,mod=1e9+7; int t,n,m,a[N]; vector <int> f[N]; class Cartesian_tree { private: int ch[N][2],stk[N],top; #define lc(x) ch[x][0] #define rc(x) ch[x][1] public: int rt; inline void build(void) { RI i; for (top=stk[1]=0,i=1;i<=n;++i) { lc(i)=rc(i)=0; while (top&&a[i]>a[stk[top]]) --top; if (top) lc(i)=rc(stk[top]),rc(stk[top])=i; else lc(i)=stk[1]; stk[++top]=i; } for (rt=stk[1],i=0;i<=m;++i) f[0][i]=1; } inline void DP(CI now) { if (!now) return; DP(lc(now)); DP(rc(now)); for (RI i=1;i<=m;++i) f[now][i]=1LL*f[lc(now)][i-1]*f[rc(now)][i]%mod,(f[now][i]+=f[now][i-1])%=mod; } #undef lc #undef rc }CT; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); for (scanf("%d",&t);t;--t) { RI i,j; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) scanf("%d",&a[i]); for (i=0;i<=n;++i) for (f[i].resize(m+1),j=0;j<=m;++j) f[i][j]=0; CT.build(); CT.DP(CT.rt); printf("%d\n",f[CT.rt][m]); } }

7|0F. Circular Xor Reversal


人类智慧构造题,想破脑袋也想不出来只能去看Tutorial

考虑定义一种操作f(l,r),可以把[l,r]的前半部分异或上后半部分的翻转,具体的:

al=alaral+1=al+1ar1al+2=al+2ar2

注意由于序列是循环的,因此l>r是合法的,只要在模意义下处理下标即可,同时我们记m=(ji+n)modn

不难发现当n为偶数时,执行f(0,n1),f(n2,n21),f(0,n1)后即可实现翻转序列

而当n为奇数时,执行f(0,n1),f(n+12,n32),f(0,n1)即可

考虑处理f(l,r),为了方便表示我们用b0m表示alr

首先考虑从m10依次操作,得到b0bm,b1bm,,bm

然后从1m1依次操作,得到b0bm,b1,,bm

然后我们对1m1重复上面的过程,得到b0bm,b1bm1,,bm12bm+22,bm+12,,bm

然后从1m22即可得到b0bm,b1bm1,,bm12bm+22,bm+12,,bm,完成了上述构造

考虑它的操作次数,为m+m1+m2++1+m2=m2+2m2<2500003,因此符合题意

#include<cstdio> #define RI register int #define CI const int& using namespace std; const int N=405; int n,a[N],ans[250005],cnt; inline void solve(int l,int r) { RI i; if (l>r) r+=n; int m=r-l,st=l,sign=1; --r; while (l<=r) { if (sign==1) { for (i=r;i>=l;--i) ans[++cnt]=i%n; ++l; } else { for (i=l;i<=r;++i) ans[++cnt]=i%n; --r; } sign^=1; } for (i=st;i<st+m/2;++i) ans[++cnt]=i%n; } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); RI i; scanf("%d",&n); solve(0,n-1); solve(n+1>>1,n-2>>1); solve(0,n-1); for (printf("%d\n",cnt),i=1;i<=cnt;++i) printf("%d ",ans[i]); return 0; }

8|0Postscript


下场找ztc和我一起打,感觉我们EZ这一届选择打ACM的好少(除了LTL和XZY两个和XYZ组成QZEZ代表队的巨佬)

现在就是写题很容易思路不清犯个SB错误,然后一下看不出来心态爆炸直接GG

连掉5场了真掉不起了呜呜呜


__EOF__

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