ccpc2024济南

<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;
}
posted @ 2024-11-01 16:51  Qzong  阅读(97)  评论(0)    收藏  举报