2024.11.12 2024 CCPC女生专场
2024 CCPC女生专场
Solved:10/13
Penalty:1299
Rank:6
今年题有这么简单吗?还是队伍变强了?
我做起来感觉比去年和前年都难。。感觉前两年至少都有 7~8 道签到,今年从 4~5 题就需要思考了。
C. CCPC
题意:重排字符串使得形如 CCPC 的子串最多。
CCPCCP...CCPC
#include<bits/stdc++.h> using namespace std; int main(){ string a; cin>>a; int n=a.length(); int cc=0,cp=0; for(int i=0;i<n;++i){ if(a[i]=='C')++cc; if(a[i]=='P')++cp; } cout<<min((cc-1)/2,cp)<<'\n'; }
A. Box
题意:多次询问一个点是否在长方体内。
#include<bits/stdc++.h> using namespace std; int main(){ ios::sync_with_stdio(0);cin.tie(0); int x1,x2,y1,y2,z1,z2; cin>>z1>>z2>>x1>>y1>>x2>>y2; if(x1>x2)swap(x1,x2); if(y1>y2)swap(y1,y2); z2+=z1; int q; cin>>q; while(q--){ int x,y,z; cin>>x>>y>>z; if(x>=x1&&x<=x2&&y>=y1&&y<=y2&&z>=z1&&z<=z2)cout<<"YES\n"; else cout<<"NO\n"; } }
H. Square Root
题意:给一个 01 串,你可以把 1 变成 0,每段连续的 1 贡献为长度的平方根,求最大答案。
容易证明,对连续的 1,拆成 1010101 或者 101011 最优。
#include<bits/stdc++.h> using namespace std; int main(){ ios::sync_with_stdio(0);cin.tie(0); string s; cin>>s; int n=s.length(),len=0; double ans=0; for(int i=0;i<n;++i){ if(s[i]=='1')++len; else if(len){ if(len&1)ans+=(len+1)/2; else ans+=len/2-1+sqrt(2); len=0; } } if(len&1)ans+=(len+1)/2; else if(len)ans+=len/2-1+sqrt(2); cout<<fixed<<setprecision(10)<<ans<<'\n'; }
M. Covering a Tree
题意:用若干条从叶子到祖先的链覆盖一棵树,使最长的链最短。
这不就是【赛道修建】的简单版本嘛()
注意到每棵子树只有一条链可以传到根。
dfs,贪心将最短的链向上延申,其他链终止在儿子处。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+5; int n,x; vector<int> e[N]; void adde(int x,int y){ e[x].push_back(y); } int ans=0; int dfs(int u){ int mn=n+1; for(int v:e[u]){ int d=dfs(v); ans=max(ans,d+1); mn=min(mn,d+1); } if(mn>n)mn=0; return mn; } void solve(){ cin>>n; for(int i=1;i<=n;++i)e[i].clear(); for(int i=2;i<=n;++i)cin>>x,adde(x,i); ans=0; int v=dfs(1); ans=max(ans,v); cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
E. Centroid Tree
题意:一棵树,根为 1,给每个点子树的重心,还原这棵树。
重心是诈骗,其实就相当于给每个点子树中的一个点。
并查集+队列从底向上维护即可。一个点如果所有子树都还原了就入队。
注意根为 1 的限制,把队列改成从大到小的优先队列即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() const int N=2e5+5; int n,f[N],c[N]; int find(int x){return x==f[x]?x:f[x]=find(f[x]);} vector<int> a[N],b[N]; void solve(){ cin>>n; priority_queue<int> q; for(int i=1;i<=n;++i)b[i].clear(); for(int i=1;i<=n;++i){ cin>>c[i]; a[i].resize(c[i]); for(int& x:a[i])cin>>x,b[x].push_back(i); if(!c[i])q.push(i); f[i]=i; } while(!q.empty()){ int u=q.top(); q.pop(); for(int x:a[u])x=find(x),cout<<u<<' '<<x<<'\n',f[x]=u; for(int x:b[u])if(!--c[x])q.push(x); } } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
L. Puzzle
题意:给四种形状的拼图,用最多的拼图使其拼成一个矩形,且每两个相邻拼图都有凹凸对应。
在题意限制下,A 只能放在角上,BC 只能放在边上且相邻放置,D 只能放在中间。
因此枚举矩形的一边长度即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() void solve(){ int a,b,c,d; cin>>a>>b>>c>>d; if(a<4)cout<<"0\n"; else{ int e=min(b,c),mx=e*2+4; for(int i=1;i<=e-1;++i){ int t=min(e-i,d/i); if(mx<(i+2)*(t+2))mx=(i+2)*(t+2); } cout<<mx<<'\n'; } } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
F. Perfect Square
题意:一个序列,取出每个数的一个约数,乘积为完全平方数,求所有方案乘积的平方根之和。$n,a_i\leq 10^6
显然可以每个质因数分别考虑。设
最终答案就是所有
不对啊,我暴力分解质因数怎么没被卡?
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() const int N=1e6+5,mod=1e9+7; int n,x,m=1e6; ll f[N][2]; int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n; for(int i=1;i<=m;++i)f[i][0]=1,f[i][1]=0; for(int i=1;i<=n;++i){ cin>>x; for(int j=2;j*j<=x;++j)if(!(x%j)){ int cnt=0; while(!(x%j))x/=j,++cnt; ll s0=0,s1=0; for(int i=0,p=1;i<=cnt;i+=2)s0+=p,p*=j; for(int i=1,p=1;i<=cnt;i+=2)s1+=p,p*=j; ll r0=(f[j][0]*s0+f[j][1]*s1%mod*j)%mod; ll r1=(f[j][1]*s0+f[j][0]*s1)%mod; f[j][0]=r0,f[j][1]=r1; } if(x>1){ ll r0=(f[x][0]+f[x][1]*x)%mod; ll r1=(f[x][1]+f[x][0])%mod; f[x][0]=r0,f[x][1]=r1; } } ll ans=1; for(int i=1;i<=m;++i)ans=ans*f[i][0]%mod; cout<<ans<<'\n'; }
G. Increasing Sequence
题意:给一个序列和一个限制
按位考虑,设当前考虑到第
如果某个
如果所有
否则继续枚举下一位。
复杂度不会算,但是过了。
题解表示复杂度是
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() const int N=1e6+5; int n; ll k,a[N],ans=0; void dfs(ll x,int d){ if(x>k)return; bool fl=1; for(int i=1;i<=n-1;++i){ ll u=a[i]^x,v=a[i+1]^x; if((u>>d)>(v>>d))return; else if((u>>d)==(v>>d)){ if(u!=v)fl=0; } } if(fl){ans+=min(1ll<<d,k-x+1);return;} dfs(x,d-1); dfs(x|(1ll<<d-1),d-1); } void solve(){ cin>>n>>k; for(int i=1;i<=n;++i)cin>>a[i]; ans=0,dfs(0,60); cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
upd:这啥啊,随便卡啊。。。
k=1e18,a={1,2,...,200000},前面的位都要枚举一遍,直接就爆了。。。。。。这都能过我也是没想到的。
K. Xiao Kai's Dream of Provincial Scholarship
题意:见题面(X
枚举
二分答案,注意到
复杂度
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() const int N=505,M=105; int n,m,id,X,Y,p,q; struct node{ string s; int id,a[3][2],pr; }a[N],b[N]; bool cmp1(node a,node b){ if(a.a[0][0]!=b.a[0][0])return a.a[0][0]>b.a[0][0]; if(a.a[0][1]!=b.a[0][1])return a.a[0][1]>b.a[0][1]; return a.s<b.s; } bool cmp2(node a,node b){ if(a.a[1][0]!=b.a[1][0])return a.a[1][0]>b.a[1][0]; if(a.a[1][1]!=b.a[1][1])return a.a[1][1]>b.a[1][1]; return a.s<b.s; } bool cmp3(node a,node b){ if(a.pr!=b.pr)return a.pr>b.pr; if(a.a[2][0]!=b.a[2][0])return a.a[2][0]>b.a[2][0]; if(a.a[2][1]!=b.a[2][1])return a.a[2][1]>b.a[2][1]; return a.s<b.s; } int buc[M]; int P(int p){return n*p/100;} bool chk(int xx,int yy){ a[id].a[0][0]+=xx,a[id].a[0][1]+=xx; a[id].a[1][0]+=yy,a[id].a[1][1]+=yy; a[id].a[2][0]+=xx+yy,a[id].a[2][1]+=xx+yy; for(int i=1;i<=n;++i)b[i]=a[i]; memset(buc,0,sizeof(buc)); for(int i=1;i<=n;++i)++buc[a[i].a[0][1]]; int rk=0,p25=0,p45=0,p75=0; for(int i=100;i>=0;--i){ rk+=buc[i]; if(!p25&&rk>=P(25))p25=i; if(!p45&&rk>=P(45))p45=i; if(!p75&&rk>=P(75))p75=i; } sort(b+1,b+n+1,cmp1); int r1=P(15),r2=P(25),r3=P(35); for(int i=1;i<=n;++i){ if(b[i].a[0][1]>=p25&&r1>0)a[b[i].id].pr+=15,--r1; else if(b[i].a[0][1]>=p45&&r2>0)a[b[i].id].pr+=10,--r2; else if(b[i].a[0][1]>=p75&&r3>0)a[b[i].id].pr+=5,--r3; } memset(buc,0,sizeof(buc)); for(int i=1;i<=n;++i)++buc[a[i].a[1][1]]; rk=0,p25=0,p45=0,p75=0; for(int i=100;i>=0;--i){ rk+=buc[i]; if(!p25&&rk>=P(25))p25=i; if(!p45&&rk>=P(45))p45=i; if(!p75&&rk>=P(75))p75=i; } sort(b+1,b+n+1,cmp2); r1=P(15),r2=P(25),r3=P(35); for(int i=1;i<=n;++i){ if(b[i].a[1][1]>=p25&&r1>0)a[b[i].id].pr+=15,--r1; else if(b[i].a[1][1]>=p45&&r2>0)a[b[i].id].pr+=10,--r2; else if(b[i].a[1][1]>=p75&&r3>0)a[b[i].id].pr+=5,--r3; } rk=0; for(int i=1;i<=n;++i)if(cmp3(a[i],a[id]))++rk; a[id].a[0][0]-=xx,a[id].a[0][1]-=xx; a[id].a[1][0]-=yy,a[id].a[1][1]-=yy; a[id].a[2][0]-=xx+yy,a[id].a[2][1]-=xx+yy; for(int i=1;i<=n;++i)a[i].pr=0; return rk<m; } bool chk(int x){ for(int i=0;i<=100-X&&i*p<=x;++i){ if(!q){ if(chk(i,100-Y))return 1; } else{ if(chk(i,min(100-Y,(x-i*p)/q)))return 1; } } return 0; } int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n; for(int i=1,x,y,z;i<=n;++i){ cin>>a[i].s,a[i].id=i; for(int j=0;j<2;++j){ cin>>x>>y>>z; a[i].a[j][0]=x+y+z; a[i].a[j][1]=x; } a[i].a[2][0]=a[i].a[0][0]+a[i].a[1][0]; a[i].a[2][1]=a[i].a[0][1]+a[i].a[1][1]; if(a[i].s=="crazyzhk")id=i,X=a[i].a[0][1],Y=a[i].a[1][1]; } cin>>m>>p>>q; int l=0,r=2e4,ans=1e9; while(l<=r){ int mid=(l+r)>>1; if(chk(mid))ans=mid,r=mid-1; else l=mid+1; } if(ans>1e6)cout<<"Surely next time"<<endl; else cout<<ans<<endl; }
I. String Duplication
题意:求一个字符串复制
打表(
所以用 SAM 求出
这题没有样例 3 我估计调到结束都调不出来
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() const int N=2e6+5,mod=998244353; struct SAM{ int cnt,c[N][26],fa[N],len[N],last; SAM(){cnt=last=1;} int ext(int ch){ int p=last,np=last=++cnt,q,nq; len[np]=len[p]+1; for(;p&&!c[p][ch];p=fa[p])c[p][ch]=np; if(!p)fa[np]=1; else{ q=c[p][ch]; if(len[p]+1==len[q])fa[np]=q; else{ nq=++cnt; len[nq]=len[p]+1; for(int i=0;i<26;++i)c[nq][i]=c[q][i]; fa[nq]=fa[q],fa[q]=fa[np]=nq; for(;p&&c[p][ch]==q;p=fa[p])c[p][ch]=nq; } } return len[np]-len[fa[np]]; } }m; int n,k; string a; int main(){ ios::sync_with_stdio(0);cin.tie(0); cin>>n>>k>>a; ll ans1=0,ans2=0,ans3=0; for(int i=0;i<n;++i)ans1+=m.ext(a[i]-'a'); ans1%=mod; ans2=ans1; for(int i=0;i<n;++i)ans2+=m.ext(a[i]-'a'); ans2%=mod; ans3=ans2; for(int i=0;i<n;++i)ans3+=m.ext(a[i]-'a'); ans3%=mod; if(k==1)cout<<ans1<<'\n'; else if(k==2)cout<<ans2<<'\n'; else cout<<((((k-2)*ans3-(k-3)*ans2)%mod)+mod)%mod<<'\n'; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战