【CF 534F】Game

Description

【CF 534F】Game_第1张图片

Solution

CF上是输出任意一个方案,这题改成了输出方案数。
其实用一个六维DP很显然的。但很麻烦。
考虑优化一下暴搜。
以为行数最多只有5行,所以可以枚举每列的状态然后再判断行的状态。
所以要先预处理每列要使值为x的所有状态。
然后把得出的一行的状态hash一下,记忆化一下,设f[x][y][z]表示做到第x列,x-1列的状态是y,现在的hash值是z,如果这个状态不为-1(初始状态为-1,表示没出现过),那么直接退出f[x][y][z]。

Code

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=21,mo=1000000007;
int i,j,k,l,t,n,m,ans;
int hang[maxn],lie[maxn],shu[1000][1000];
int ci[11],er[11],f[21][32][170000],a[21];
//bool bz[21][32][170000];
int dfs(int x,int y){
    int t=0,i;
    fo(i,1,n)t+=a[i]*ci[i-1];
    if(x==m+1){
        fo(i,1,n)if(a[i]!=hang[i])return 0;
        return 1;
    }
    if(f[x][y][t]>=0)return f[x][y][t];
    f[x][y][t]=0;
    fo(i,1,n){
        if(a[i]>hang[i]||a[i]+(m-x+2)/2
    }
    fo(i,1,shu[lie[x]][0]){
        fo(j,1,n)if(!(y&er[j])&&(shu[lie[x]][i]&er[j]))a[j]++;
        f[x][y][t]=(f[x][y][t]+dfs(x+1,shu[lie[x]][i]))%mo;
        fo(j,1,n)if(!(y&er[j])&&(shu[lie[x]][i]&er[j]))a[j]--;
    }
    return f[x][y][t];
}
int main(){
    scanf("%d%d",&n,&m);
    fo(i,1,n)scanf("%d",&hang[i]);
    fo(i,1,m)scanf("%d",&lie[i]);ci[0]=1;
    fo(i,1,n)er[i]=1<
    fo(i,0,(1<
        int u=0;
        fo(j,1,5)if((er[j]&i)&&(!(er[j-1]&i)))u++;
        shu[u][++shu[u][0]]=i;
    }
    memset(f,255,sizeof(f));
    printf("%d\n",dfs(1,0));
}

你可能感兴趣的:(DP,状态压缩DP,记忆化搜索,暴搜,CF)