bzoj2669: [cqoi2012]局部极小值

DP太恐怖恐怖怖了。。。。。

2^28肯定不兹瓷

考虑对于'X'的点不会超过8个,用二进制表示

f[i][j]表示当前填了第i个数字,状态为j的方案数

由小到大填

f[i+1][j]=f[i][j]*num[j] num表示当前这个状态,有多少位置可以填。为了保证合法,没被填的'X'周围的格子肯定不能填。

f[i+1][j^(1<<k)]=f[i][j] 填在第k个'X'

然后还要容斥一波,因为无法保证'.'的位置不是局部最小值,这个用dfs搜出每一种情况容斥即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const LL mod=12345678;
const int dx[8]={-1,0,1,0,1,1,-1,-1};
const int dy[8]={0,-1,0,1,1,-1,1,-1};

int n,m;char ss[10][10];
int id,maxp,mp[10][10];
bool v[10][10];LL num[1100];
void init()
{
    id=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(ss[i][j]=='X')mp[i][j]=++id;
    maxp=(1<<id)-1;
    for(int zt=0;zt<=maxp;zt++)
    {
        num[zt]=0;
        memset(v,true,sizeof(v));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(ss[i][j]=='X')
                {
                    v[i][j]=false; num[zt]++;
                    if(!(zt&(1<<mp[i][j]-1)))
                    {
                        for(int k=0;k<=7;k++)
                        {
                            int ti=i+dx[k],tj=j+dy[k];
                            if(ti>0&&ti<=n&&tj>0&&tj<=m&&v[ti][tj]==true)
                                v[ti][tj]=false, num[zt]++;
                        }
                    }
                }
        num[zt]=n*m-num[zt];
    }
}

LL f[40][1100];
LL DP()
{
    init();
    memset(f,0,sizeof(f));f[0][0]=1;
    for(int i=0;i<n*m;i++)
        for(int zt=0;zt<=maxp;zt++)
            if(f[i][zt]>0)
            {
                int cc=0;
                for(int k=0;k<id;k++)
                    if(!(zt&(1<<k)))
                        f[i+1][zt^(1<<k)]=(f[i+1][zt^(1<<k)]+f[i][zt])%mod;
                    else
                        cc++;
                
                f[i+1][zt]=(f[i+1][zt]+f[i][zt]*max(num[zt]-(i-cc),0LL))%mod;
            }
    return f[n*m][maxp];
}

LL ans;
void dfs(int x,int y,int c)//容斥
{
    if(x==n+1)
    {
        if(c%2==0)ans=(ans+DP())%mod;
        else ans=((ans-DP())%mod+mod)%mod;
        return ;
    }
    bool bk=true;
    if(ss[x][y]=='X')bk=false;
    else
    {
        for(int k=0;k<=7;k++)
        {
            int tx=x+dx[k],ty=y+dy[k];
            if(tx>0&&tx<=n&&ty>0&&ty<=m&&ss[tx][ty]=='X')
                {bk=false;break;}
        }
    }
    
    if(y==m)dfs(x+1,1,c);
    else     dfs(x,y+1,c);
    if(bk==true)
    {
        ss[x][y]='X';
        if(y==m)dfs(x+1,1,c+1);
        else     dfs(x,y+1,c+1);
        ss[x][y]='.';
    }
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%s",ss[i]+1);
    ans=0;
    dfs(1,1,0);
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-09-18 15:36  AKCqhzdy  阅读(132)  评论(0编辑  收藏  举报