2024.11.12 2024 CCPC女生專場

EssnSlaryt發表於2024-11-13

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

顯然可以每個質因數分別考慮。設 \(f_{i,0/1}\) 表示質因數 \(i\) 的次數為偶數或奇數時平方因子的平方根之和。每個數質因數分解後 dp 即可。

最終答案就是所有 \(f_{i,0}\) 的乘積。

不對啊,我暴力分解質因數怎麼沒被卡?

#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

題意:給一個序列和一個限制 \(k\),求滿足 \(\{a_1\oplus x,\dots,a_n\oplus x\}\) 為不降序列且 \(0\leq x\leq k\)\(x\) 的數量。\(n\leq 2\times 10^5, k\leq 10^{18}\)

按位考慮,設當前考慮到第 \(d\) 位前面是 \(x\)
如果某個 \(a_i\oplus x\) 的前 \(d\) 位大於 \(a_{i+1}\oplus x\) 的前 \(d\) 位,後面就不用列舉了,必然不滿足。
如果所有 \(a_i\oplus x\) 的前 \(d\) 位都小於 \(a_{i+1}\oplus x\) 的前 \(d\) 位或者 \(a_i=a_{i+1}\),後面也不用列舉了,必然滿足。
否則繼續列舉下一位。

複雜度不會算,但是過了。
題解表示複雜度是 \(O(n\log k)\)

#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

列舉 \(p\)\(q\) 的使用次數,然後按題意模擬即可 TLE on 7。

二分答案,注意到 \(p,q\) 用得越多越好,所以對一個確定的答案列舉 \(p\) 的使用次數然後直接求出 \(q\) 的最大使用次數即可。

複雜度 \(O(nm\log n\log m)\)

#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

題意:求一個字串複製 \(m\) 次的本質不同子串數量。

打表(\(m=1,2,3,4,5\))或者手玩可以發現 \(m\geq 2\) 後答案形成了等差數列。

所以用 SAM 求出 \(m=2,3\) 的答案即可。記得特判 \(m=1\)

這題沒有樣例 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';
}

相關文章