这题好像状压的做法比较的无脑?但想记录一下容斥的做法,感觉自己对于容斥简直一无所知。这道题目容斥的解法我也是看了题解才会的。如有雷同,是我看的(*/ω\*)我们可以首先枚举当前字符串与给定的哪 \(k\) 个匹配(给定的范围很小,枚举一下也只要 \(2^{n}\))。但这样我们求出的是至少与 \(k\) 个字符串匹配的方案数,因为在保证与这 \(k\) 个字符串匹配的时候,我们并没有要求说与其他的 \(n - k\) 个字符串不相匹配。

  我们令上面求出来的数组叫做 \(num[k]\) ,现在要求出恰好与 \(k\) 个串匹配的数组 \(ans[k]\)。一个感觉是 \(num[k] = ans[k] + ans[k + 1] + ... + ans[n]\),但事实上并不是如此。之前我们只考虑 \(k\) 个字符串求出来的 \(num[k]\) 中,有许多重复的方案。例如 \(?a\) 与 \(b?\) 的例子,在枚举到第一个字符串的时候,我们会统计 \(ba\) 一次,而在枚举第二个的时候,我们又会统计到 \(ba\) 一次。那么 \(ans[x]\) 究竟在 \(num[k]\) 中被统计了多少次?应当是 \(C(x, k)\) 次,因为这枚举的 \(k\) 个可能是 \(x\) 个当中的任意 \(k\) 个。

#include <bits/stdc++.h>
using namespace std;
#define maxn 2000
#define int long long
#define mod 1000003
int n, K, len, num[maxn], ans[maxn], C[maxn][maxn];
string s[maxn], S[maxn]; int read()
{
int x = , k = ;
char c; c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void pre()
{
for(int i = ; i < maxn; i ++) C[i][] = ;
for(int i = ; i < maxn; i ++)
for(int j = ; j < maxn; j ++)
C[i][j] = (C[i - ][j - ] + C[i - ][j]) % mod;
} int Qpow(int x, int timer)
{
int base = ;
for(; timer; timer >>= , x = x * x % mod)
if(timer & ) base = base * x % mod;
return base;
} void dfs(int now, int tot)
{
if(now == n + )
{
int cnt = ;
for(int j = ; j < len; j ++)
{
int t = -;
for(int i = ; i <= tot; i ++)
{
int x = S[i][j] - 'a'; if(x == -) x = -;
if(t != - && (x != - && x != t)) return;
if(t == -) t = x;
}
if(t == -) cnt ++;
}
num[tot] = (num[tot] + Qpow(, cnt)) % mod;
return;
}
dfs(now + , tot);
S[tot + ] = s[now]; dfs(now + , tot + );
} void init()
{
memset(ans, , sizeof(ans));
memset(num, , sizeof(num));
} signed main()
{
int T = read(); pre();
while(T --)
{
n = read(), K = read(); init();
for(int i = ; i <= n; i ++) cin >> s[i];
len = s[].length();
dfs(, );
for(int i = n; i >= K; i --)
{
int t = num[i];
for(int j = i + ; j <= n; j ++)
t = (t - (C[j][i] * ans[j]) % mod + mod) % mod;
ans[i] = t;
}
printf("%lld\n", ans[K]);
}
return ;
}

【题解】SDOI2009Bill的挑战的更多相关文章

  1. poj 3253 Fence Repair 贪心 最小堆 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=3253 题解 本题是<挑战程序设计>一书的例题 根据树中描述 所有切割的代价 可以形成一颗二叉树 而最后的代价总和是与子节点和深 ...

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

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

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

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

  4. noip做题记录+挑战一句话题解?

    因为灵巧实在太弱辽不得不做点noip续下命QQAQQQ 2018 积木大赛/铺设道路 傻逼原题? 然后傻逼的我居然检查了半天是不是有陷阱最后花了差不多一个小时才做掉我做过的原题...真的傻逼了我:( ...

  5. TYVJ-P1864 守卫者的挑战 题解

    P1864 [Poetize I]守卫者的挑战 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜 ...

  6. POJ 2386 Lake Counting 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=2386 <挑战程序设计竞赛>习题 题目描述Description Due to recent rains, water has ...

  7. poj 3069 Saruman's Army 贪心 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=3069 题解 题目可以考虑贪心 尽可能的根据题意选择靠右边的点 注意 开始无标记点 寻找左侧第一个没覆盖的点 再来推算既可能靠右的标记点为一 ...

  8. poj 2431 Expedition 贪心 优先队列 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=2431 题解 朴素想法就是dfs 经过该点的时候决定是否加油 中间加了一点剪枝 如果加油次数已经比已知最少的加油次数要大或者等于了 那么就剪 ...

  9. poj 1182 食物链 并查集 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=1182 题解 可以考虑使用并查集解决 但是并不是简单的记录是否同一组的这般使用 每个动物都有三个并查集 自己 天敌 捕食 并查集 那么在获得 ...

随机推荐

  1. 手机蓝牙APP扫描设备的时候异常断开(未完成)

    1.手机蓝牙APP打开立马就出现异常,测试在公司有这个问题,在宿舍没这个问题,怀疑是公司设备太多,导致扫描空间不够,或者扫描到奇怪的设备.数组越界之类,明天用log看一下 2. 看样子出了一个erro ...

  2. 限时购校验小工具&dubbo异步调用实现限

    本文来自网易云社区 作者:张伟 背景 限时购是网易考拉目前比较常用的促销形式,但是前期创建一个限时购活动时需要各个BU按照指定的Excel格式进行选品提报,为了保证提报数据准确,运营需要人肉校验很多信 ...

  3. Xuan.UWP.Framework(2)

    上一章主要介绍了Xuan.UWP.Framework.ImageLib的基本用法,这一章具体来看些Xuan.UWP.Framework.ImageLib的使用. 一.首先看下Xuan.UWP.Fram ...

  4. react组件性能

    一.渲染原理 二.性能优化 三.Immutable在性能优化中的作用

  5. 如何利用Navicat导入/导出mssql中的数据

    sqlserver,在第一次使用该软件进行"连接"的时候,会提示安装"Microsoft Sqlsever Navicat Client.",这时直接点击&qu ...

  6. python 水仙花

    #简单def narcissus(): for n in range(100, 1000, 1): a, b, c = n//100, (n//10)%10, (n%100)%10 if a ** 3 ...

  7. C 基本运算

    一 算术运算 C语言一共有34种运算符 包括了常见的加减乘除运算 1. 加法运算+ 除开能做加法运算 还能表示正号: +5, +90 2. 减法运算- 除开能做减法运算 还能表示符号: -10, -2 ...

  8. [JSON].exists( keyPath )

    语法:[JSON].exists( keyPath ) 返回:[True | False] 说明:检测指定键名路径是否存在 示例: Set jsonObj = toJson("{div:{' ...

  9. 【转】: 探索Lua5.2内部实现:虚拟机指令(3) Upvalues & Globals

    在编译期,如果要访问变量a时,会依照以下的顺序决定变量a的类型: a是当前函数的local变量 a是外层函数的local变量,那么a是当前函数的upvalue a是全局变量 local变量本身就存在于 ...

  10. Docker学习记录3: 搭建 Private Registry

    恩, Private Registry 特别好搭建, 只要依照官方文档, 很容易安装... https://docs.docker.com/registry/deploying/ 5000是个常用的端 ...