BZOJ 1879 [Sdoi2009]Bill的挑战 ——状压DP

本来打算好好写写SDOI的DP题目,但是忒难了,

太难了,就写的这三道题仿佛是可做的。

生在弱省真是兴奋。

这题目直接状压,f[i][j]表示匹配到i,状态集合为j的方案数,然后递推即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
 
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
 
const int md=1000003;
int dp[2][1<<16],T,n,m,len,g[60][30],ans=0;
char s[16][60];
 
void print(int x)
{
    F(i,0,n-1) printf("%d",(x>>i)&1);
}
 
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        ans=0;memset(g,0,sizeof g);
        scanf("%d%d",&n,&m);
        F(i,0,n-1) scanf("%s",s[i]+1);
        len=strlen(s[1]+1);
        F(i,1,len) F(j,0,25)
        {
            F(k,0,n-1)
            if (s[k][i]=='?'||(s[k][i]-'a')==j)
                g[i][j]|=(1<<k);
        }
        int now=1,pre=0;
        memset(dp[now],0,sizeof dp[now]);
        dp[now][(1<<n)-1]=1;
        F(i,1,len)
        {
            now^=1; pre^=1;
            memset(dp[now],0,sizeof dp[now]);
            F(j,0,(1<<n)-1)
                if (dp[pre][j])
                    F(k,0,25)
                        (dp[now][j&g[i][k]]+=dp[pre][j])%=md;
        }
        F(i,0,(1<<n)-1)
        {
            int t=i,cnt=0;
            while (t) {cnt+=(t&1);t>>=1;}
            if (cnt==m) (ans+=dp[now][i])%=md;
        }
        printf("%d\n",ans);
    }
}

  

posted @ 2017-03-01 23:17  SfailSth  阅读(349)  评论(0编辑  收藏  举报