zoukankan      html  css  js  c++  java
  • SDOI 2009 BIll的挑战

    题目描述 Description

    Sheng bill不仅有惊人的心算能力,还可以轻松地完成各种统计。在昨天的比赛中,你凭借优秀的程序与他打成了平局,这导致Sheng bill极度的不满。于是他再次挑战你。这次你可不能输!

    这次,比赛规则是这样的:

    给N个长度相同的字符串(由小写英文字母和′?′组成),S1,S2,...,SN,求与这N个串中的刚好K个串匹配的字符串T的个数(答案模1000003)。

    若字符串Sx(1 ≤ x ≤ N)和T匹配,满足以下条件:

    1. Sx.length = T.length。

    2. 对于任意的1 ≤ i ≤ Sx.length,满足Sx[i]=′?′或者Sx[i]= T[i]。

    其中T只包含小写英文字母。

    输入描述 Input Description

    本题包含多组数据。

    第一行:一个整数T,表示数据的个数。

    对于每组数据:

    第一行:两个整数,N和K(含义如题目表述)。

    接下来N行:每行一个字符串。

    输出描述 Output Description

    对于每组数据,输出方案数目(共T行)。

    样例输入 Sample Input

    1

    2 1

    a?

    ?b

    样例输出 Sample Output

    50

    数据范围及提示 Data Size & Hint

    对于30%的数据,T ≤ 5,N ≤ 5,字符串长度≤ 20;

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

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

      写代码用一个小时,dp转移写错,调了一个多小时,把lsany写成any,半小时改过来一个,半小时后发现还有一个没改过来。别人写的程序比我短一半,结果后几个点效率还比我好(前几个比我差)。存天理,灭蒟蒻啊。

      好了,我们来看一下这一个题目。我们可以一个一个字母的枚举,在枚举的过程中,我们不妨进行如下的动态规划。f[i][j]表示,当前已经处理了i位,匹配状态为j。j是我们用状态压缩得到的一个数字,就是用n个二进制位,分别表示一个字符串是否被匹配。

      状态转移的时候,我们把j所表示的已经被匹配的字符串分离出来,然后处理他们的下一位。建一个动态数组,用来储存下一位是X的字符串有哪几个。处理完后,将所有下一位是?的字符串直接判定为被匹配,然后枚举下一个字母,进行动态转移。

      输出的时候,枚举第几位被匹配就好。

      代码:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<string>
     4 #include<vector>
     5 using namespace std;
     6 
     7 const int mod = 1000003;
     8 
     9 int f[51][65536];
    10 int t, n, len, k;
    11 int ans;
    12 vector<int> G[27];       //动态数组
    13 char c[16][52];
    14 
    15 void dp() {           
    16     memset(f, 0, sizeof(f));
    17     int num = 0;
    18     for (int i = 0; i < 27; i++)  //预先处理第一位
    19         G[i].clear();
    20     for (int i = 1; i <= n; i++) {
    21         if (c[i][0] == '?') 
    22             G[26].push_back(i);
    23         else G[(int)c[i][0] - 97].push_back(i);
    24     }
    25     int any = 0;
    26     for (int i = 0; i < G[26].size(); i++) 
    27         any = any + (1 << (G[26][i] - 1));   //any表示下一位为?的字符串的匹配状态
    28     for (int i = 0; i < 26; i++) {
    29         int lsany = any;   //lsany表示分别下一位为a - z时的匹配状体
    30         for (int j = 0; j < G[i].size(); j++) 
    31             lsany = lsany + (1 << (G[i][j] - 1));
    32         if (lsany != 0)
    33             f[1][lsany] = f[1][lsany] % mod + 1;   //动态转移
    34         if (lsany > num) num = lsany;
    35     }
    36     for (int i = 1; i < len; i++) 
    37         for (int j = 1; j <= num; j++) 
    38             if (f[i][j] != 0)  {
    39                 for (int k = 0; k < 27; k++)
    40                     G[k].clear();
    41                 for (int k = 0; k < n; k++)
    42                     if ((1 & j >> k) == 1)
    43                         if (c[k+1][i] == '?')
    44                             G[26].push_back(k+1);
    45                         else G[(int) c[k+1][i] - 97].push_back(k+1);
    46                 int any = 0;
    47                 for (int k = 0; k < G[26].size(); k++)
    48                     any = any + (1 << (G[26][k] - 1));
    49                 for (int k = 0; k < 26; k++) {
    50                     int lsany = any;
    51                     for (int w = 0; w < G[k].size(); w++)
    52                         lsany = lsany + (1 << (G[k][w] - 1));
    53                     if (lsany != 0)
    54                         f[i+1][lsany] =(f[i+1][lsany]  + f[i][j])  % mod;
    55                 }
    56             }
    57 }
    58 
    59 
    60 void print(int now, int where, int w){   //输出
    61     if (now == k) {ans =(ans + f[len][w]) % mod; return;}
    62     if (where > n) return;
    63     print(now+1, where+1, w + (1 << (where - 1)));
    64     print(now, where+1, w);
    65 }
    66 
    67 int main() {
    68     ios::sync_with_stdio;
    69     cin >> t;
    70     for (int o = 0; o < t; o++) {
    71         cin >> n >> k;
    72         for (int i = 1; i <= n; i++)
    73             cin >> c[i];
    74         len = 0;
    75         while ((int)c[1][len] > 96 || c[1][len] == '?')
    76             len++;
    77         dp();
    78         ans = 0;
    79         print(0, 1, 0);
    80         cout << ans << "
    ";
    81     }
    82     return 0;
    83 }
  • 相关阅读:
    Java和JavaScript的时间互传
    session.createQuery()不执行和java.lang.reflect.InvocationTargetException
    [转载]标签a的href和onclick
    [转载]前端优化指南
    POJ1328-Radar Installation
    POJ1323-Game Prediction
    codinglife主题小修改和有意思的博客挂件
    POJ1050-To the Max
    HDU4323-Magic Number(levenshtein distance-编辑距离)
    HDU2955-Robberies
  • 原文地址:https://www.cnblogs.com/xstsow/p/4414755.html
Copyright © 2011-2022 走看看