• Bzoj1879 [Sdoi2009]Bill的挑战


    Time Limit: 4 Sec  Memory Limit: 64 MB
    Submit: 724  Solved: 363

    Description

    Input

    本题包含多组数据。 第一行:一个整数T,表示数据的个数。 对于每组数据: 第一行:两个整数,N和K(含义如题目表述)。 接下来N行:每行一个字符串。

    Output

    1
    2 1
    a?
    ?b

    Sample Input

    50

    Sample Output

    对于30%的数据,T ≤ 5,N ≤ 5,字符串长度≤ 20;
    对于70%的数据,T ≤ 5,N ≤ 13,字符串长度≤ 30;
    对于100%的数据,T ≤ 5,N ≤ 15,字符串长度≤ 50。

    HINT

     

    Source

    动规 状压DP

    这题简直思路清奇。

    刚开始想的是预处理出每两个串之间能否匹配,以及每个串能匹配它之前出现的多少串,然后DP。←想来好复杂,而且可能还要容斥,那就是超复杂了。

      (说不定也能强行做出来呢 http://www.cnblogs.com/SilverNebula/p/6001294.html)

    再一看数据范围,啊,状压你好。

    所有串的长度一样,所以可以统一处理,预处理g[i][j]=x表示字符j可以和x集合内的串的第i位匹配

    f[匹配长度][集合]=方案数

    f[0][全满集合]=1

    f[i][ k&g[i-1][j] ]+=f[递推位数i-1][枚举集合k]

     1 /*by SilverN*/
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 const int mod=1e6+3;
    10 const int mxn=100010;
    11 int f[51][1<<15];
    12 int g[51][27];
    13 char s[16][52];
    14 int T,n,K;
    15 int main(){
    16     int i,j;
    17     scanf("%d",&T);
    18     while(T--){
    19         memset(f,0,sizeof f);
    20         scanf("%d%d",&n,&K);
    21         for(i=0;i<n;i++){scanf("%s",s[i]);}
    22         int len=strlen(s[0]);
    23         for(i=0;i<len;i++)//长度 
    24             for(int k=0;k<26;k++){//字母     
    25                 g[i][k]=0;
    26                 for(j=0;j<n;j++){//
    27                     if(s[j][i]=='?' || s[j][i]==k+'a')g[i][k]|=(1<<j);
    28                 }
    29             }
    30         int ed=(1<<n)-1;
    31         f[0][ed]=1;
    32         for(i=1;i<=len;i++){
    33             for(int k=0;k<=ed;k++){
    34                 if(f[i-1][k])
    35                 for(j=0;j<26;j++){
    36                     (f[i][k&g[i-1][j]]+=f[i-1][k])%=mod;
    37                 }
    38             }
    39         }
    40         int ans=0;
    41         for(int k=0;k<=ed;k++){
    42             int tmp=k,cnt=0;
    43             while(tmp){
    44                 cnt++;
    45                 tmp-=tmp&-tmp;
    46             }
    47             if(cnt==K)ans=(ans+f[len][k])%mod;
    48         }
    49         printf("%d
    ",ans);
    50     }
    51     return 0;
    52 }
    本文为博主原创文章,转载请注明出处。
  • 相关阅读:
    poj_1836 动态规划
    动态规划——最长上升子序列
    poj_3260 动态规划
    poj_3628 动态规划
    动态规划——背包问题
    poj_2559 单调栈
    poj_3415 后缀数组+单调栈
    poj_2823 线段树
    poj_2823 单调队列
    poj_3250 单调栈
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6482928.html
Copyright © 2020-2023  润新知