BZOJ1879 Bill的挑战

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1879

本来是一道水题(~~~~(>_<)~~~~)。

开始SB了,敲了个AC自动机dp,MLE

发现数据中 '?' 好多呀 ~~~~(>_<)~~~~ 空间变$O(len^2)$

然后去想朴素dp,枚举一下那些集合和T匹配,然后$O(n cdot 2^n)$ dp,又W又T一是爽。

TLE 40:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

#define c(w,i) ((w>>i)&1)
#define mod 1000003
#define LL long long
#define MP(x,y) make_pair(x,y)
#define fir first
#define sec second

using namespace std;

int n,K,cnt;
char S[110][110],T[110];
LL f[110][26];
vector<pair<int,char> > v[110];

LL calc(int w){
    for(int i=0;i<n;i++) T[i]='?';
    for(int i=0;i<cnt;i++)
        if(c(w,i)){
            for(int j=0;j<n;j++)
                if(S[i][j]!='?'){
                    if(T[j]=='?'||T[j]==S[i][j])
                        T[j]=S[i][j];
                    else return 0;
                }
        }
    memset(f,0,sizeof(f));
    for(int i=0,fl;i<cnt;i++)
        if(!c(w,i)){
            fl=0;
            for(int j=0;j<n;j++){
                if(S[i][j]!='?' && T[j]!='?' && S[i][j]!=T[j])
                    fl=1;
            }
            if(!fl){
                for(int j=0;j<n;j++){
                    if(S[i][j]!='?')
                        v[j].push_back(MP(i,S[i][j]));
                }
            }
        }
    f[0][0]=1;
    for(int i=0;i<n;i++){
        for(int w=0;w<(1<<cnt);w++)
            if(f[i][w]){
                for(char c='a';c<='z';c++){
                    if(T[i]!='?'&&T[i]!=c) continue;
                    int now=0;
                    for(int j=v[i].size()-1;~j;j--)
                        if(v[i][j].sec!=c) now|=(1<<v[i][j].fir);
                    f[i+1][now|w]+=f[i][w];
                }
            }
    }
    return f[n][((1<<cnt)-1)&~w];
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&cnt,&K);
        for(int i=0;i<cnt;i++) scanf("%s",S[i]);
        n=strlen(S[0]);
        LL ans=0;
        for(int w=0;w<(1<<cnt);w++){
            int tmp=0;
            for(int i=0;i<cnt;i++)
                if(c(w,i)) tmp++;
            if(tmp!=K) continue;
            ans=(ans+calc(w))%mod;
        }
        printf("%lld
",ans);
    }
    return 0;
}
View Code

然后发现我是SB

没有看完题呀,原来长度都相同。

直接裸dp f[i][S] 表示T的前i位,n个串的匹配状态为S的方案数。

注意因为长度都相同,只能从第一位开始匹配呀!!!

然后水了。

AC 100:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

#define c(w,i) ((w>>i)&1)
#define mod 1000003

using namespace std;

int n,K,cnt,f[60][65536],cv[60][26];
char S[20][60];

int main(){
    freopen("test.in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        memset(f,0,sizeof(f));
        scanf("%d%d",&cnt,&K);
        for(int i=0;i<cnt;i++) scanf("%s",S[i]);
        n=strlen(S[0]);
        for(int i=0;i<n;i++){
            for(int t=0;t<26;t++){
                cv[i][t]=0;
                for(int j=0;j<cnt;j++){
                    if(S[j][i]=='?'
                        ||S[j][i]==t+'a') cv[i][t]|=(1<<j);
                }
            }
        }
        f[0][(1<<cnt)-1]=1;
        for(int i=0;i<n;i++)
            for(int j=0;j<(1<<cnt);j++){
                if(f[i][j]){
                    for(int t=0;t<26;t++)
                        (f[i+1][j&cv[i][t]]+=f[i][j])%=mod;
                }
            }
        int ans=0;
        for(int w=0;w<(1<<cnt);w++){
            int tmp=0;
            for(int i=0;i<cnt;i++) if(c(w,i)) tmp++;
            if(tmp==K) (ans+=f[n][w])%=mod;
        }
        printf("%d
",ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lawyer/p/4551188.html