hdu 多校状压dp

由于行只有12,所以对行进行状态压缩

0表示这行没有被扎过,也不存在没有爆的气球

1表示这行没有被扎过,存在没有爆的气球

2表示这行被扎过

枚举每一列 对于第i行第j列的气球

2种转移 扎和不扎

扎<---0,1

不扎<---0,1

#include<algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include  <stdio.h>
#include   <math.h>
#include   <time.h>
#include   <vector>
#include   <bitset>
#include    <queue>
#include      <map>
#include      <set>
using namespace std;

typedef long long ll;
const int N=22,M=531442;
const ll outbuf=1000000000000ll;
int n,m,q,k,p3[N],num2[M],num1[M],w[M][N];
ll f[N][M],fac[N],Ans[N];
char wq[N][N];

void solve()
{
    scanf("%d%d%d",&n,&m,&q);
    k=p3[n];
    for(int i=0;i<=20;i++)
        Ans[i]=0;
    for(int i=1;i<=n;i++)
        scanf(" %s",wq[i]+1);
    for(int i=0;i<=m;i++)
        for(int j=0;j<k;j++)
            f[i][j]=0;
//    cout<<k<<endl;
    f[0][0]=1;
    for(int i=1;i<=m;i++)
    {
        for(int s=0;s<k;s++)
        {
            if(f[i-1][s]&&num1[s]<=m-i+1)//s这种状态存在,且没被扎的气球数少于后面可以扎的气球数,每一列至多扎一个
            {
                int nxt=s;
                for(int j=1;j<=n;j++)
                    if(w[s][j]==0&&wq[j][i]=='Q')//不扎
                        nxt+=p3[j-1];
                f[i][nxt]+=f[i-1][s];
                for(int j=1;j<=n;j++)
                    if(wq[j][i]=='Q'&&w[s][j]!=2)
                    {
                        nxt=s+(2-w[s][j])*p3[j-1]//
                        f[i][nxt]+=f[i-1][s];
                    }
            }
        }
    }
    for(int s=0;s<k;s++)
        if(f[m][s]&&num1[s]==0)
            Ans[num2[s]]+=f[m][s];
    for(int i=1;i<=q;i++)
    {
        __int128 t=Ans[i];t*=fac[i];
        if(t>outbuf)
            printf("%lld%012lld\n",ll(t/outbuf),ll(t%outbuf));
        else
            printf("%lld\n",ll(t));
//        printf("%lld\n",Ans[i]*fac[i]);//,cout<<" "<<Ans[i]<<endl;
    }
//    puts("");
}

int main()
{
    p3[0]=1;
    for(int i=1;i<=12;i++)
        p3[i]=p3[i-1]*3;
    fac[0]=1;
    for(int i=1;i<=12;i++)
        fac[i]=fac[i-1]*i;
    k=p3[12];
    for(int s=0;s<k;s++)
    {
        int nm2=0,nm1=0;
        for(int i=1;i<=12;i++)
        {
            w[s][i]=(s/p3[i-1]%3);
            if(w[s][i]==1)
                nm1++;
            else if(w[s][i]==2)
                nm2++;
        }
        num2[s]=nm2;num1[s]=nm1;
    }
    int t;cin>>t;
    while(t--)
        solve();
//    cout<<clock()<<endl;
    return 0;
}

 

posted @ 2018-08-18 12:43  电竞毒奶  阅读(293)  评论(0编辑  收藏  举报