• 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
    ",ans);
        return 0;
    }
  • 相关阅读:
    闭包
    this
    函数声明,表达式,构造函数
    算法学习_栈
    LeetCode刷题_140
    2020/3/20 刷题
    2020/3/19 刷题
    2020/3/13_C++实验课
    刷题(主要是DFS) 2020年3月12日
    DFS的一些题2020/3/11
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/9669243.html
Copyright © 2020-2023  润新知