1 条题解

  • 0
    @ 2025-8-24 21:37:40

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar RainFestival
    时代的眼泪|我们所过的每个平凡的日常,也许就是连续发生的奇迹

    搬运于2025-08-24 21:37:40,当前版本为作者最后更新于2019-05-04 21:34:47,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这道题一看就是其实是一个dp,轮廓线dp

    设点i,j上一个轮廓线为u

    那么如果u的第m位与第0位(二进制从低到高,第k位价值2^k)

    都不与当前要填的数不同,就可以进行状态转移

    我们再用滚动数组优化空间即可

    附上带有简单优化常数的我不优化有一个点过不去代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #define mod 376544743
    using namespace std;
    long long dp[5][300000],a[15],ans,sp1[100005],sp2[100005];
    int n,m,kk,now,maxs,s1,s2,can,bo;
    inline void update(register int x1,register int x2,register int x,register int y)
    {
        dp[now][x2]=(dp[now][x2]+dp[now^1][x1])%mod;
    }
    inline void put(register int x,register int y,register int can)
    {
        if (y/a[m-1]!=x&&(y%kk!=x||can)) update(y,(y*kk+x)%a[m],x,y);
    } 
    inline int check(int x,int y)
    {
        while (x>0||y>0)
        {
            if (x%kk==y%kk) return 0;
            x=x/kk,y=y/kk;
        }
        return 1;
    }
    int main()
    {
        srand(time(NULL));
        scanf("%d%d%d",&n,&m,&kk);
        if (kk==2)
        {
            //printf("%d",rand()%2);
            //return 0;
            bo=1;
            for (register int i=1;i<=m;++i)
            {
                //scanf("%d",&sp1[i]);
                char ch=getchar();
                while (ch!='0'&&ch!='1') ch=getchar();
                sp1[i]=ch-48;
                if (sp1[i]==sp1[i-1]) bo=0;
            } 
                
            for (register int i=1;i<=m;++i)
            {
                //scanf("%d",&sp2[i]);
                char ch=getchar();
                while (ch!='0'&&ch!='1') ch=getchar();
                sp2[i]=ch-48;
                if (sp2[i]==sp2[i-1]) bo=0;
            }  
            for (int i=1;i<=m;++i)
                if ((sp1[i]+n)%2==sp2[i]) bo=0;
            printf("%d\n",bo);
            return 0;    
        }
        a[0]=1;
        maxs=1;
        for (int i=1;i<=m-1;++i)
            a[i]=a[i-1]*kk;
        a[m]=a[m-1]*kk;
        maxs=a[m]-1;
        for (int i=1;i<=m;++i)
        {
            int x,y=-1;
            scanf("%d",&x);
            if (i!=1&&x==y)
            {
                printf("%d\n",0);
                return 0;
            }
            s1=s1*kk+x;
            y=x;
        }
        for (int i=1;i<=m;++i)
        {
            int x,y=-1;
            scanf("%d",&x);
            if (i!=1&&x==y)
            {
                printf("%d\n",0);
                return 0;
            }
            s2=s2*kk+x;
            y=x;
        }
        dp[0][s1]=1;
        now=0;
        for (register int i=1;i<n;++i)
            for (register int j=1;j<=m;++j)
            {
            	if (i==1&&j!=m) continue;
            	if (i==n-1&&j==m) break;
            	if (j==m) can=1;
            	else can=0;
                now=now^1;
                for (register int k=0;k<=maxs;++k) dp[now][k]=0;
            	for (register int k=0;k<=maxs;++k)
            	{
            		if (dp[now^1][k]==0) continue;//去掉对答案无贡献的状态,节约时间
                    for (register int p=0;p<kk;++p)
            	        put(p,k,can);
                }	   
            }
        for (register int i=0;i<=maxs;++i)
            if (check(i,s2)) ans=(ans+dp[now][i])%mod;
        printf("%lld\n",ans);
        return 0;
    }
    

    然后就accepted了

    时间808ms,内存3860KB,代码长度4.08KB

    感谢大佬们的观赏

    • 1

    信息

    ID
    1812
    时间
    2000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者