1 条题解

  • 0
    @ 2025-8-24 21:31:24

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Owen_codeisking
    前OIer/ACMer/柚子厨/酒姬民

    搬运于2025-08-24 21:31:24,当前版本为作者最后更新于2018-07-18 13:44:56,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    前排警告

    这是写给刚学的我看的,大佬请自动忽略

    人生第一道状压dpdp 互不侵犯是学术交流过的

    本蒟蒻今天在机房听到状压dpdp,感觉很高大上……其实就是位运算高大上一点

    解释一下位运算:

    & 给个例子

    0110101+1010011=00100010110101+1010011=0010001,返回值为1717

    n<<kn<<knn左移kk位,相当于给nn乘上2k2^k

    n>>kn>>knn右移kk位,相当于给nn除以2k2^k后向下取整

    解释一下状压dpdp

    它的基本思想就是用二进制来优美地暴力枚举出现的方案,

    若二进制下第ii位有赋值11,则一行的第ii列有放牛

    那么f[i][j]f[i][j]表示在前ii行中(包括ii)在jj个状态下的最大方案数

    易得f[i][j]=(f[i][j]+f[i1][k]) mod pf[i][j]=(f[i][j]+f[i-1][k])\ mod\ pp=109p=10^9jj是第ii行的状态,kk是第i1i-1行的状态)

    所以我们还要再预处理一下,g[i]g[i]表示第ii个状态是否存在,判断条件是

    g[i]=g[i]= !(i!(i&(i>>1))!(i(i>>1))!(i&(i<<1))(i<<1))

    目标状态:f[n][i]f[n][i]全部相加

    Code Below:Code \ Below:

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int p=100000000;
    ll f[13][1<<12],n,m;
    ll g[1<<12],h[1<<12],a[13][13];
    ll F[13];
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			scanf("%d",&a[i][j]);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			F[i]=(F[i]<<1)+a[i][j];
    	for(int i=0;i<(1<<m);i++){
    		if(!(i&(i>>1))&&!(i&(i<<1))){
    			g[i]=1;
    			if((i&F[1])==i) f[1][i]=1;
    		}
    	}
    	for(int x=2;x<=n;x++)
    		for(int j=0;j<(1<<m);j++)
    			if(((j&F[x-1])==j)&&g[j])
    				for(int k=0;k<(1<<m);k++)
    					if(((k&F[x])==k)&&!(j&k)&&g[k]){
    						f[x][k]=(f[x][k]+f[x-1][j])%p;
    					}
    	int ans=0;
    	for(int i=0;i<(1<<m);i++)
    		ans=(ans+f[n][i])%p;
    	printf("%d\n",ans);
        return 0;
    }
    
    • 1

    信息

    ID
    848
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者