训练实况

<Dashboard - CCPC Jinan Test - Codeforces>

\(C\)

对于构造指令使得它能执行若干条指令这种问题,我们确实挺容易想到将其拆分为 \(+1\) 以及 \(\times 2\) 来解决。

问题就在于如何转化为这个问题。

对于这种类似于图的推进结构,最简单的永远是链。

我们发现要使栈为空,最简单的方式是从头到尾走两遍。

至此我们就有了整个问题的基础结构。

现在的问题就是在只增加一个指令的情况下完成 \(\times 2\) 以及 \(+1\) 。

\(\times 2\) 便是让其回头一次。

\(+1\) 便是让链变长一点。

#include<cstdio>
const int N=666;
struct node{
	int a,b,c,d;
}t[N];
int tp,st[N];
int main(){
	int n;
	scanf("%d",&n);
	if(n==1){
		printf("1\nHALT; PUSH 127 GOTO 1");
		return 0;
	}
	n=(n-1)/2;
	while(n){
		st[++tp]=n&1;
		n>>=1;
	}
	int tot=0;
	t[++tot]={1,2,1,1};
	for(int i=tp-1;i>=1;i--){
		t[tot]={tot,tot+1,tot,1};
		tot++;
		t[tot]={tot,tot+1,tot,tot};
		if(st[i]){
			tot++;
			t[tot]={tot,tot+1,tot,tot};
		}
	}
	printf("%d\n",tot+1);
	for(int i=1;i<=tot;i++)printf("POP %d GOTO %d; PUSH %d GOTO %d\n",t[i].a,t[i].b,t[i].c,t[i].d);
	printf("HALT; PUSH 127 GOTO 1");
	return 0;
}

\(D\)

事实上,如果对 \(f_{u,v}=(cnt,w)\) 表示在栈顶为 \(u\) 的时候进入指令 \(v\) 后弹出 \(u\) 并进入 \(w\) 指令需要的次数,它的状态数是 \(O(n^2)\) 的。

#include<cstdio>
const int N=1055;
int n;
struct go{
    int a,b,c,d;
}tt[N];
struct node{
    int a,b;
}f[N][N];
int cnt=0,flag=1;
const int maxn=1024*1024+111;
const int mod=998244353;
node dfs(int u,int v){
    if(++cnt>=maxn)flag=0;
    if(!flag)return {0,0};
    if(f[u][v].a)return f[u][v];
    int top=tt[v].c,go=tt[v].d,ans=0;
    if(u==0&&tt[v].a==0)return f[u][v]={1,0};
    if(tt[v].a==u)return f[u][v]={1,tt[v].b};
    node now1=dfs(tt[v].c,tt[v].d);
    if(now1.b==0)return f[u][v]={now1.a+1,0};
    else {
        node now2=dfs(u,now1.b);
        return f[u][v]={(now1.a+now2.a+1)%mod,now2.b};
    }
}
char s[10];
int main(){
    // freopen("a.in","r",stdin);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        if(s[0]=='P'){
            scanf("%d GOTO %d; PUSH %d GOTO %d",&tt[i].a,&tt[i].b,&tt[i].c,&tt[i].d);
        }
        else {
            scanf(" PUSH %d GOTO %d",&tt[i].c,&tt[i].d);
        }
    }
    int ans=dfs(0,1).a;
    if(flag)printf("%d\n",ans%mod);
    else puts("-1");
    return 0;
}

\(H\)

此题略微抽象。

首先考虑一位会受到什么影响。

它只会受到前一位如果进位 \(+1\) 的影响。

但如果要考虑前一位是否能 \(+1\) 就又得去枚举更前面的顺序,但我们不关心他如何能 \(+1\) 。

我们仔细思考后发现,如果前一位能自由选择,那么自由选择的时候一定能通过改变若干顺序,来不改变前面的值来达到目的。

因此我们设立三种状态 \(0,1,2\) ,分别表示一定要进位,不一定要进位,能自由选择进位与否。

再套上数位 \(dp\) 常用套路即可。

#include<cstdio>
#include<cstring>
const int M=19;
int s1[M+2],s2[M+2];
long long f[M+2][2][3];
void work(){
    long long x,y;
    int tp1=0,tp2=0;
    scanf("%lld%lld",&x,&y);
    for(int i=1;i<=M;i++)s1[i]=s2[i]=0;
    while(x)s1[++tp1]=x%10,x/=10;
    while(y)s2[++tp2]=y%10,y/=10;
    memset(f,0,sizeof f);
    f[0][0][0]=1;
    for(int i=1;i<=M;i++){
        if(s1[i]==0){
            for(int k=0;k<=s2[i];k++){
                if(k<=3){
                    f[i][0][0]+=f[i-1][0][0];
                    f[i][0][0]+=f[i-1][0][1];
                    f[i][0][0]+=f[i-1][0][2];
                }
                else if(k==4){
                    f[i][0][0]+=f[i-1][0][0];
                    f[i][0][2]+=f[i-1][0][1];
                    f[i][0][2]+=f[i-1][0][2];
                }
                else {
                    f[i][0][1]+=f[i-1][0][0];
                    f[i][0][1]+=f[i-1][0][1];
                    f[i][0][1]+=f[i-1][0][2];
                }
            }
            for(int k=0;k<s2[i];k++){
                if(k<=3){
                    f[i][0][0]+=f[i-1][1][0];
                    f[i][0][0]+=f[i-1][1][1];
                    f[i][0][0]+=f[i-1][1][2];
                }
                else if(k==4){
                    f[i][0][0]+=f[i-1][1][0];
                    f[i][0][2]+=f[i-1][1][1];
                    f[i][0][2]+=f[i-1][1][2];
                }
                else {
                    f[i][0][1]+=f[i-1][1][0];
                    f[i][0][1]+=f[i-1][1][1];
                    f[i][0][1]+=f[i-1][1][2];
                }
            }
            for(int k=s2[i]+1;k<=9;k++){
                if(k<=3){
                    f[i][1][0]+=f[i-1][0][0];
                    f[i][1][0]+=f[i-1][0][1];
                    f[i][1][0]+=f[i-1][0][2];
                }
                else if(k==4){
                    f[i][1][0]+=f[i-1][0][0];
                    f[i][1][2]+=f[i-1][0][1];
                    f[i][1][2]+=f[i-1][0][2];
                }
                else {
                    f[i][1][1]+=f[i-1][0][0];
                    f[i][1][1]+=f[i-1][0][1];
                    f[i][1][1]+=f[i-1][0][2];
                }
            }
            for(int k=s2[i];k<=9;k++){
                if(k<=3){
                    f[i][1][0]+=f[i-1][1][0];
                    f[i][1][0]+=f[i-1][1][1];
                    f[i][1][0]+=f[i-1][1][2];
                }
                else if(k==4){
                    f[i][1][0]+=f[i-1][1][0];
                    f[i][1][2]+=f[i-1][1][1];
                    f[i][1][2]+=f[i-1][1][2];
                }
                else {
                    f[i][1][1]+=f[i-1][1][0];
                    f[i][1][1]+=f[i-1][1][1];
                    f[i][1][1]+=f[i-1][1][2];
                }
            }
        }
        else if(s1[i]==1){
            for(int k=0;k<=s2[i];k++){
                if(k==1){
                    f[i][0][0]+=f[i-1][0][0];
                    f[i][0][0]+=f[i-1][0][1];
                    f[i][0][0]+=f[i-1][0][2];
                }
                else if(k<=4){
                    f[i][0][0]+=f[i-1][0][1];
                    f[i][0][0]+=f[i-1][0][2];
                }
                else {
                    f[i][0][1]+=f[i-1][0][1];
                    f[i][0][1]+=f[i-1][0][2];
                }
            }
            for(int k=0;k<s2[i];k++){
                if(k==1){
                    f[i][0][0]+=f[i-1][1][0];
                    f[i][0][0]+=f[i-1][1][1];
                    f[i][0][0]+=f[i-1][1][2];
                }
                else if(k<=4){
                    f[i][0][0]+=f[i-1][1][1];
                    f[i][0][0]+=f[i-1][1][2];
                }
                else {
                    f[i][0][1]+=f[i-1][1][1];
                    f[i][0][1]+=f[i-1][1][2];
                }
            }
            for(int k=s2[i]+1;k<=9;k++){
                if(k==1){
                    f[i][1][0]+=f[i-1][0][0];
                    f[i][1][0]+=f[i-1][0][1];
                    f[i][1][0]+=f[i-1][0][2];
                }
                else if(k<=4){
                    f[i][1][0]+=f[i-1][0][1];
                    f[i][1][0]+=f[i-1][0][2];
                }
                else {
                    f[i][1][1]+=f[i-1][0][1];
                    f[i][1][1]+=f[i-1][0][2];
                }
            }
            for(int k=s2[i];k<=9;k++){
                if(k==1){
                    f[i][1][0]+=f[i-1][1][0];
                    f[i][1][0]+=f[i-1][1][1];
                    f[i][1][0]+=f[i-1][1][2];
                }
                else if(k<=4){
                    f[i][1][0]+=f[i-1][1][1];
                    f[i][1][0]+=f[i-1][1][2];
                }
                else {
                    f[i][1][1]+=f[i-1][1][1];
                    f[i][1][1]+=f[i-1][1][2];
                }
            }
        }
        else {
            for(int k=0;k<=s2[i];k++){
                if(k==s1[i]-1){
                    f[i][0][0]+=f[i-1][0][1];
                    f[i][0][0]+=f[i-1][0][2];
                }
                else if(k==s1[i]){
                    f[i][0][0]+=f[i-1][0][0];
                    f[i][0][0]+=f[i-1][0][2];
                }
            }
            for(int k=0;k<s2[i];k++){
                if(k==s1[i]-1){
                    f[i][0][0]+=f[i-1][1][1];
                    f[i][0][0]+=f[i-1][1][2];
                }
                else if(k==s1[i]){
                    f[i][0][0]+=f[i-1][1][0];
                    f[i][0][0]+=f[i-1][1][2];
                }
            }
            for(int k=s2[i]+1;k<=9;k++){
                if(k==s1[i]-1){
                    f[i][1][0]+=f[i-1][0][1];
                    f[i][1][0]+=f[i-1][0][2];
                }
                else if(k==s1[i]){
                    f[i][1][0]+=f[i-1][0][0];
                    f[i][1][0]+=f[i-1][0][2];
                }
            }
            for(int k=s2[i];k<=9;k++){
                if(k==s1[i]-1){
                    f[i][1][0]+=f[i-1][1][1];
                    f[i][1][0]+=f[i-1][1][2];
                }
                else if(k==s1[i]){
                    f[i][1][0]+=f[i-1][1][0];
                    f[i][1][0]+=f[i-1][1][2];
                }
            }
        }
    }
    printf("%lld\n",f[M][0][0]);
}
int main(){
    // freopen("a.in","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)work();
    return 0;
}

\(F\)

问题可以转化为需要删去的个数。

假定目前考虑的所有数最小值为 \(x\) 。

那么只有在集合里全是 \(x\) 的倍数时需要删。

当然,有可能得删多次。

直接搜索即可。

#include<cstdio>
const int N=100010,M=100000;
const int mod=998244353;
int ksm(int x,int y){
    int ans=1;
    while(y){
        if(y&1)ans=1ll*ans*x%mod;
        x=1ll*x*x%mod;
        y>>=1;
    }
    return ans;
}
int pre[N],ipre[N];
void init(){
    pre[0]=1;
    for(int i=1;i<=M;i++)pre[i]=1ll*pre[i-1]*i%mod;
    ipre[M]=ksm(pre[M],mod-2);
    for(int i=M;i>=1;i--)ipre[i-1]=1ll*ipre[i]*i%mod;
}
int C(int x,int y){
    if(y>x)return 0;
    return 1ll*pre[x]*ipre[x-y]%mod*ipre[y]%mod;
}
int n,m;
int dfs(int x,int y){
    if(1ll*x*y>m)return 0;
    if(y==1)return 1;
    int ans=C(m/x-1,y-1);
    for(int k=2;k*x<=m;k++){
        ans=(ans+dfs(k*x,y-1))%mod;
    }
    return ans;
}
int main(){
    init();
    scanf("%d%d",&m,&n);
    int ans=0;
    for(int i=1;i*n<=m;i++){
        if(i*n<=m)ans=(ans+dfs(i,n))%mod;
    }
    printf("%d\n",(1ll*C(m,n)*n%mod+mod-ans)%mod);
    return 0;
}

Codeforces Round 978 (Div. 2)

\(D\)

还是忽略了一种情况。

尽可能往下界靠。

还是一样的,小情况构造,大情况类似。

#include<cstdio>
void work(){
    int n;
    scanf("%d",&n);
    int flag=-1;
    for(int i=1;i+2<=n;i+=2){
        if(n%2==1&&i==n-4){
            break;
        }
        int x,y;
        printf("? %d %d\n",i,i+1);
        fflush(stdout);
        scanf("%d",&x);
        printf("? %d %d\n",i+1,i);
        fflush(stdout);
        scanf("%d",&y);
        if(x!=y){
            flag=i;
            break;
        }
    }
    if(flag==-1&&n%2==1){
        // printf("! %d\n",n);
        if(n==3){
            printf("! %d\n",3);
            fflush(stdout);
            return ;
        }
        int x,y,z;
        printf("? %d %d\n",n-4,n-3);
        fflush(stdout);
        scanf("%d",&x);
        printf("? %d %d\n",n-3,n-2);
        fflush(stdout);
        scanf("%d",&y);
        printf("? %d %d\n",n-2,n-4);
        fflush(stdout);
        scanf("%d",&z);
        if(x+y+z==0||x+y+z==2){
            int u,v;
            printf("? %d %d\n",n-4,n-2);
            fflush(stdout);
            scanf("%d",&u);
            printf("? %d %d\n",n-3,n-4);
            fflush(stdout);
            scanf("%d",&v);
            int ans;
            if(u!=z&&v!=x)ans=n-4;
            else if(u==z&&v!=x)ans=n-3;
            else ans=n-2;
            printf("! %d\n",ans);
            fflush(stdout);
            return ;
        }
        else {
            flag=n-1;
        }
        // return ;
    }
    if(flag==-1)flag=n-1;
    int id;
    if(flag==1)id=n;
    else id=1;
    int x,y;
    printf("? %d %d\n",flag,id);
    fflush(stdout);
    scanf("%d",&x);     
    printf("? %d %d\n",id,flag);
    fflush(stdout);
    scanf("%d",&y);
    if(x==y){
        printf("! %d\n",flag+1);
        fflush(stdout);
        return ;
    }
    else {
        printf("! %d\n",flag);
        fflush(stdout);
        return ;
    }
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--)work();
    return 0;
}

\(E\)

考虑拆到行和列上

#include<cstdio>
#include<vector>
const int N=200020;
const int mod=1e9+7;
int f[N],val[N],ans[N];
int n,m,k,q;
int find(int x){
    while(x!=f[x])x=f[x]=f[f[x]];
    return x;
}
std::vector<int>t[N];
void work(){
    scanf("%d%d%d%d",&n,&m,&k,&q);
    for(int i=1;i<=n+m;i++)f[i]=i,val[i]=0,t[i].clear(),t[i].push_back(i);
    int now=n+m-1,all=0;
    if(k==0)printf("%d\n",ans[now]);
    for(int i=1,u,v,w;i<=k+q;i++){
        scanf("%d%d%d",&u,&v,&w);
        v+=n;
        int x=find(u),y=find(v);
        if(x==y){
            // puts("yes");
            // printf("%d %d %d %d %d\n",u,v,w,val[u],val[v]);
            if((val[u]^val[v])!=w){
                now=-1;
            }
        }
        else {
            now--;
            if(t[x].size()<t[y].size()){
                int tot=val[u]^val[v]^w;
                for(int j:t[x])t[y].push_back(j),val[j]^=tot;
                // printf("%d %d %d %d %d %d == \n",val[u],val[v],val[w],u,v,w);
                f[x]=y;
            }
            else {
                int tot=val[u]^val[v]^w;
                for(int j:t[y])t[x].push_back(j),val[j]^=tot;
                // printf("%d %d %d %d %d %d == \n",val[u],val[v],val[w],u,v,w);
                f[y]=x;
            }
        }
        if(i>=k){
            if(now>=0)printf("%d\n",ans[now]);
            else printf("%d\n",0);
        }
        // printf("%d %d %d\n",now,i,find(x));
        // for(int j=1;j<=n+m;j++)printf("%d ",val[j]);
        // puts("");
    }
}
int main(){
    // freopen("a.in","r",stdin);
    int t;
    scanf("%d",&t);
    ans[0]=1,ans[1]=(1<<30)%mod;
    for(int i=2;i<=200000;i++)ans[i]=1ll*ans[i-1]*ans[1]%mod;
    while(t--)work();
    return 0;
}

D - Swap and Erase

首先需要机制的猜想不会连续交换

#include<cstdio>
const int N=200020;
int f[N][2];
int n,a[N];
int min(int x,int y){
    return x<y?x:y;
}
const int inf=100000009;
void work(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",a+i);
    }
    f[1][0]=f[1][1]=1;
    for(int i=2;i<=n;i++){
        f[i][0]=min(f[i-1][1]+1-(a[i]==a[i-2]),f[i-1][0]+1-(a[i]==a[i-1]));
        f[i][1]=min(f[i-2][0]+1-(a[i]==a[i-2])+1,i>=3?f[i-2][1]+1-(a[i]==a[i-3])+1:inf)+1;
    }
    printf("%d\n",min(f[n][0],f[n][1]));
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--)work();
    return 0;
}

Codeforces Round 1012 (Div. 1)

\(B\)

那我问你

如果正常做有循环

那你就不能考虑它没有循环的情况?

可以找一下最不可能有循环的地方

最不可能被影响到的地方

这不一定需要只通过脑袋想

这还可以通过样例来模拟

就比如这题

sum和最小的地方的后一位或许是个好地方

还有 \(rotate\) 这个函数或许值得参考

还有一些函数写在主程序里的做法

posted @ 2025-03-25 10:10  Qzong  阅读(58)  评论(1)    收藏  举报