[SDOI2009]Bill的挑战——全网唯一 一篇容斥题解
全网唯一一篇容斥题解
Description
Solution
看到这个题,大部分人想的是状压dp
但是我是个蒟蒻没想到,就用容斥切掉了。
并且复杂度比一般状压低,
(其实这个容斥的算法,提出来源于ywy_c_asm)
(然而我知道了这个算法,竟然和他写的不一样,而且比他跑的快)
进入正题:
我们需要统计恰好满足匹配k个的情况。
那么,我们可以先找出来,恰好满足n个,n-1,n-2。。。k个的情况。
分别记为ans[i]
ans[i]怎么算呢?
先给出公式:
ans[i]=cal(i)-∑C(j,i)×ans[j] 其中,i+1<=j<=n
cal(i)表示,从n个中任意选择i个,对于所有选择的情况,的方案数的和。
cal(i)可以dfs暴力C(n,i)枚举,每次统计答案。计入tot
void dfs(int x,int has){
if(x==n+){
if(has!=up) return;
ll lp=;
for(int j=;j<=len;j++){
las=-;
for(int i=;i<=up;i++){
if(a[mem[i]][j]!='?'){
if(las==-){
las=a[mem[i]][j]-'a';
}
else if(las!=a[mem[i]][j]-'a') return;
}
}
if(las==-)lp=(lp*)%mod;
}
(tot+=lp)%=mod;
return;
}
if(has<up) {
mem[++cnt]=x;
dfs(x+,has+);
mem[cnt--]=;
}
if(n-x>=up-has) dfs(x+,has);
}
至于后面减去的部分。就是容斥的内容了。
大家可以自己画一个韦恩图理解一下。
这里有一个例子:n=4
现在我们要算ans[2],也就是恰好匹配2个的T的方案数
就是黄色的部分。
红色的数字是这个区域被算cal(i)的次数。
可见,三个点的重复区域,由于有C(3,2)种方法选到,所以会被算C(3,2)次。
所以减去所有的ans[3]即可。
其他情况同理。
最后输出ans[1]
组合数打表。
理论复杂度:
O(n×len×2^15)
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=;
const int M=;
const int mod=;
char a[N][M];
int len;
int n,t,k;
int mem[N],cnt;
ll ans[N];
ll c[N][N];
ll sum;
ll tot;//tot measures
int up;//choose
int las;
void dfs(int x,int has){//dfs计算tot
if(x==n+){
if(has!=up) return;
ll lp=;
for(int j=;j<=len;j++){
las=-;
for(int i=;i<=up;i++){
if(a[mem[i]][j]!='?'){
if(las==-){
las=a[mem[i]][j]-'a';
}
else if(las!=a[mem[i]][j]-'a') return;//两个字符不一样,无合法方案
}
}
if(las==-)lp=(lp*)%mod;//如果都是‘?’可以随便填,否则只有一种
}
(tot+=lp)%=mod;
return;
}
if(has<up) {
mem[++cnt]=x;
dfs(x+,has+);
mem[cnt--]=;
}
if(n-x>=up-has) dfs(x+,has);
} void clear(){
memset(ans,,sizeof ans);
sum=;
len=;
}
int main()
{
for(int i=;i<=N-;i++){
c[i][]=;
for(int j=;j<=i;j++){
c[i][j]=(c[i-][j-]+c[i-][j])%mod;
}
}
scanf("%d",&t);
while(t--){
clear();//清空数组,其实没有必要
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%s",a[i]+);
}
len=strlen(a[]+);//长度 for(int i=n;i>=k;i--){//ans[i]计算
tot=;up=i;
dfs(,);
sum=;
for(int j=i+;j<=n;j++){//容斥的处理
(sum+=c[j][i]*ans[j])%=mod;
}
ans[i]=(tot-sum+mod)%mod;
}
printf("%lld\n",ans[k]);
}
return ;
}
[SDOI2009]Bill的挑战——全网唯一 一篇容斥题解的更多相关文章
- [BZOJ3523][Poi2014]KLO-Bricks——全网唯一 一篇O(n)题解+bzoj最优解
Description 有n种颜色的砖块,第i种颜色的砖块有a[i]个,你需要把他们放成一排,使得相邻两个砖块的颜色不相同,限定第一个砖块的颜色是start,最后一个砖块的颜色是end,请构造出一种合 ...
- 【BZOJ1879】[SDOI2009]Bill的挑战(动态规划)
[BZOJ1879][SDOI2009]Bill的挑战(动态规划) 题面 BZOJ 洛谷 题解 本来还想着容斥来着,这个数据范围直接暴力就好.设\(f[i][S]\)表示当前填到了第\(i\)位,和\ ...
- bzoj千题计划207:bzoj1879: [Sdoi2009]Bill的挑战
http://www.lydsy.com/JudgeOnline/problem.php?id=1879 f[i][j] 表示匹配了i个字符,匹配字符串的状态为j的方案数 枚举下一个字符是什么 计算加 ...
- 【BZOJ1879】[Sdoi2009]Bill的挑战 状压DP
[BZOJ1879][Sdoi2009]Bill的挑战 Description Input 本题包含多组数据. 第一行:一个整数T,表示数据的个数. 对于每组数据: 第一行:两个整数,N和K(含 ...
- bzoj 1879: [Sdoi2009]Bill的挑战
题目链接 bzoj 1879: [Sdoi2009]Bill的挑战 题解 n<=15,装压吧 对所有字符串进行装压 可以预处理一个数组can[i][j]表示所有的字符串中,有哪些可以在第i位匹配 ...
- [bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp
Bill的挑战 bzoj-1879 Sdoi-2009 题目大意: 注释:$1\le t \le 5$,$1\le m \le 15$,$1\le length \le 50$. 想法: 又是一个看数 ...
- [LuoguP2167][SDOI2009]Bill的挑战_容斥原理/状压dp
Bill的挑战 题目链接:https://www.luogu.org/problem/P2167 数据范围:略. 题解: 因为$k$特别小,想到状压. 状压的方式也非常简单,就是暴力枚举. 但是会不会 ...
- 【[SDOI2009]Bill的挑战】
一看题解好像全是状压DP,那么我就来补充一个容斥写法吧 乍一看,好像是水题,枚举选哪k个串,然后判断 1,如果这k个串中至少两个串某位置确定且不相同,答案显然为02,如果这个位置只被有且仅有一个串确定 ...
- bzoj 1879 [Sdoi2009]Bill的挑战(状压DP)
Description Input 本题包含多组数据. 第一行:一个整数T,表示数据的个数. 对于每组数据: 第一行:两个整数,N和K(含义如题目表述). 接下来N行:每行一个字符串. Output ...
随机推荐
- 20155210 实验一 逆向与Bof基础
20155210 实验一 逆向与Bof基础 实验内容 1.直接修改程序机器指令,改变程序执行流程 下载目标文件pwn1,反汇编 利用objdump -d pwn1对pwn1进行反汇编 得到: 8048 ...
- EZ 2018 05 01 NOIP2018 模拟赛(十一)
莫名其妙暴涨Rating 其实题目都挺好挺简单的,但是越简单就越容易ZZ 不理解问什么第一题这么多人找环 不过T2是真心细节题,T3太难了 题目戳这里 T1 仔细分析题意发现那个交换规则就是废话,如果 ...
- Wannafly挑战赛26-F-msc的棋盘[最小割转化dp]
题意 一个大小为 \(n*m\) 的棋盘,知道每一列放了多少棋子,求有多少摆放方案满足要求. \(n,m\leq 50\) . 分析 如果是求是否有方案的话可以考虑网络流,行列连边,列容量为 \(b_ ...
- pycharm自动生成头文件注释
1.在file->settings->file and code templates->python script即可自定制pycharm创建文件自动生成的头文件注释信息 2.创建p ...
- python面试题(四)
一.数据类型 1.字典 1.1 现有字典 dict={‘a’:24,‘g’:52,‘i’:12,‘k’:33}请按字典中的 value 值进行排序? sorted(dict.items(),key=l ...
- zabbix监控docker容器状态
前言:前段时间在部署zabbix,有个需求就是需要监控容器的状态 也就是cpu 内存 io的占用,于是就自己写了一个脚本,以及模板,在这里分享一下 嘿嘿 : ) 废话我也就不多说,直接开始 首选,za ...
- PAT甲题题解-1127. ZigZagging on a Tree (30)-中序、后序建树
根据中序遍历和前序遍历确定一棵二叉树,然后按“层次遍历”序列输出.输出规则:除根节点外,接下来每层的节点输出顺序是:先从左到右,再从右到左,交替输出 #include <iostream> ...
- C. Smallest Word
链接 [http://codeforces.com/contest/1043/problem/C] 题意 给你一个只包含a,b的字符串,有一种操作把第1个字符到第i个字符的子串进行反转,问要使最后字符 ...
- Game over 作业
终于有一篇不拼代码拼码字的作业了,哈哈哈..... 从寒假到这次结束,经历的博客及编码作业的过程 前面七次作业做个分类: 通往博客园和C++的第一步. 知识点:让我们对C++做一个预习,在学C++前有 ...
- js实现进度条效果
需求分析: 最近学习javascript客户端脚本语言,学到了两个定时器函数setInterval()和setTimeout(),回想起以前在网页上看到的进度条效果可以使用定时器来实现,所以完成了进度 ...