题目描述 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 << "\n";
81     }
82     return 0;
83 }

转载于:https://www.cnblogs.com/xstsow/p/4414755.html

SDOI 2009 BIll的挑战相关推荐

  1. [BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)

    [BZOJ 1879][SDOI 2009]Bill的挑战 Description Solution 1.考虑状压的方式. 方案1:如果我们把每一个字符串压起来,用一个布尔数组表示与每一个字母的匹配关 ...

  2. SDOI 2009 ED

    SDOI 2009 E&D 小E与小W进行一项名为 EDE DED 游戏. 游戏的规则如下:桌子上有 2n2n2n堆石子,编号为 1∼2n1 \sim 2n1∼2n.其中,为了方便起见,我们将 ...

  3. bzoj千题计划207:bzoj1879: [Sdoi2009]Bill的挑战

    http://www.lydsy.com/JudgeOnline/problem.php?id=1879 f[i][j] 表示匹配了i个字符,匹配字符串的状态为j的方案数 枚举下一个字符是什么 计算加 ...

  4. P2167 [SDOI2009]Bill的挑战

    P2167 [SDOI2009]Bill的挑战 题意: 有n个长度一样的字符串,字符串的每一位是?或者确定的字母,,求与这 N 个串中的刚好 K 个串匹配的字符串 T 的个数 1<=N<= ...

  5. 【SDOI2009】Bill的挑战

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

  6. [SDOI2009]Bill的挑战——全网唯一 一篇容斥题解

    全网唯一一篇容斥题解 Description Solution 看到这个题,大部分人想的是状压dp 但是我是个蒟蒻没想到,就用容斥切掉了. 并且复杂度比一般状压低, (其实这个容斥的算法,提出来源于y ...

  7. 2017.7.27 bill的挑战 失败总结

    做了两个状压dp,有点门路了 就是说一般状压dp都需要枚举前面的状态,然后利用插数的思想递推,一般想清楚转移就差不多了  ,它就是利用状态把等效的情况压在了一起,和位运算的优势来dp 这个题一开始老是 ...

  8. 洛谷 P2167 [SDOI2009]Bill的挑战

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

  9. SDOI 2009 学校食堂(好难的状压QAQ

    题目描述 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴.当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数 ...

最新文章

  1. 为什么Bugs没有被修复?
  2. 第十一讲 二阶齐次线性ODE相关理论
  3. 2050 Programming Competition (CCPC)
  4. Test Article
  5. how to verify that Listener is entry point of application
  6. scala和java像不像_关于Java和Scala同步的五件事你不知道
  7. 4.namespace
  8. 工具开发:勿以善小而不为
  9. 将 Java Spring Framework 应用程序迁移到 Windows Azure
  10. 为什么程序员做外包会被瞧不起?
  11. 前端如何压缩图片质量
  12. Iphone蓝牙通信
  13. AxureRP9 主功能界面
  14. 从集合角度看二项式系数之和的计算
  15. 20个优秀手机界面扁平化设计,让你一秒看懂扁平化
  16. 一个程序员应该怎样去学习和掌握计算机英语呢
  17. 浅谈GFS之---读写文件流程
  18. 【巨人的肩膀上制造世界】——10——Unity3D实用插件之Vectrosity,轻松便捷的实现2D/3D画线功能
  19. java的Map接口
  20. speccpu测试工具介绍和使用说明

热门文章

  1. Hibernate框架之HQL查询与Criteria 查询的区别
  2. ActiveMQ消息回流
  3. (17)System Verilog枚举类型enum详解
  4. (8)UART发送verilog与Systemverilog编码
  5. journalctl -xe mysql_journalctl 日志查看方法
  6. python高手之路(第3版)_Python高手之路(第3版)
  7. python做审计底稿视频_最新Python教学视频,每天自学俩小时,让你offer拿到手软...
  8. 用winformz时间格式不正确_霜冻不可怕,用生态防寒布正确预防减少损失
  9. 基于Flash的ECC纠错算法基本原理及软件C语言算法和硬件Verilog实现(PPT在主页可下载)
  10. 【嵌入式Linux】嵌入式Linux应用开发基础知识之I2C应用编程和SMBus协议及AP3216C应用编程