UOJ #214 合唱队形 (概率期望计数、DP、Min-Max容斥)
9个月的心头大恨终于切掉了!!!!
非常好的一道题,不知为何uoj上被点了70个差评。
题目链接: http://uoj.ac/problem/214
题目大意: 请自行阅读。
题解:
官方题解讲得相当清楚,这里补充一下自己的一些理解。
首先来看\(O(2^{n-m}\times poly(n,m))\)的做法。
一种理解方式是官方题解。
设\(s\)为总共的课程个数(\(n\)个字符串的总长度),\(p(S)\)表示结尾位置为集合\(S\)的串全部匹配一共需要完成多少个不同的课程。设\(f(t)\)表示\(t\)时刻整个过程没有终止的概率,\(prob(S,t)\)表示\(S\)集合结尾的串在\(t\)时刻或者之前已经完成匹配的概率。\(ans\)为答案。
\]
计算即可。
其实还有另外一种理解方式。我们要求的是所有串匹配时间最小值的期望,根据Min-Max容斥,我们可以通过枚举子集转化成对每个子集求该子集内串匹配时间最大值的期望,然后转化成每一时刻没结束的概率。
然后来看更难的\(O(2^m\times poly(n,m))\)做法。
对于所有\(p(S)\)相同的\(S\), 其对答案的贡献没有区别。
因此对于所有\(k\),考虑计算\(p(S)=k\)的\(S\)的个数。
然后直接dp即可。
代码错误记录: 注意solution1如果\(n-m=16\)的话数组要开到\(2^{17}\).
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define llong long long
using namespace std;
const int N = 30;
const int S = 26;
const int P = 998244353;
bool ok[N+3];
int f[N+3][S+3];
char str[N+3];
char a[N+3];
llong fact[2000003],finv[2000003],inv[2000003];
int cnt[(1<<17)+3];
int n,m,s;
llong quickpow(llong x,llong y)
{
llong cur = x,ret = 1ll;
for(int i=0; y; i++)
{
if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
cur = cur*cur%P;
}
return ret;
}
llong comb(llong x,llong y) {return x<0 || y<0 || x<y ? 0ll : fact[x]*finv[y]%P*finv[x-y]%P;}
namespace Solution1
{
int ff[N+3][S+3];
llong ans;
void solve()
{
ans = 0ll;
for(int i=1; i<(1<<(n-m+1)); i++)
{
llong cur = 0ll; bool gg = false;
for(int j=0; j<=n-m; j++)
{
if(i&(1<<j))
{
for(int k=0; k<m; k++)
{
ff[j+k][a[k]-96] = true;
if(f[j+k][a[k]-96]==false) {gg = true; break;}
}
if(gg==true) break;
}
}
if(gg)
{
for(int j=0; j<n; j++)
{
for(int k=1; k<=S; k++)
{
ff[j][k] = false;
}
}
continue;
}
int num = 0;
for(int j=0; j<n; j++)
{
for(int k=1; k<=S; k++)
{
if(ff[j][k]==true) {num++;}
}
}
for(int j=1; j<=num; j++)
{
llong tmp = (llong)s*inv[j]%P*comb(num,j)%P;
if(!(j&1)) {cur = (cur+tmp)%P;}
else {cur = (cur-tmp+P)%P;}
}
for(int j=0; j<n; j++)
{
for(int k=1; k<=S; k++)
{
ff[j][k] = false;
}
}
if(cnt[i]&1) {ans = (ans-cur+P)%P;}
else {ans = (ans+cur+P)%P;}
}
printf("%lld\n",ans);
}
}
namespace Solution2
{
#define U ((1<<m)-1)
const int M = 14;
llong dp[N+3][(1<<M)+3][N*M+3];
bool ff[N+3][M+3];
void update(llong &x,llong y) {x = (x+y)%P;}
void solve()
{
llong ans = 0ll;
dp[m-1][0][0] = 1ll;
for(int i=m-1; i<n; i++)
{
for(int j=0; j<(1<<m); j++)
{
bool okk = true;
for(int k=0; k<m; k++) if((j&(1<<k)) && ok[i-k-1]==false) {okk = false; break;}
if(!okk) continue;
int p = 0;
for(int k=0; k<m; k++)
{
if(j&(1<<k))
{
for(int l=0; l<m; l++)
{
ff[i-k-1-m+1+l][a[l]-96] = true;
}
}
}
for(int l=0; l<m; l++)
{
if(ff[i-m+1+l][a[l]-96]==false)
{
p++;
}
}
for(int k=0; k<m; k++)
{
if(j&(1<<k))
{
for(int l=0; l<m; l++)
{
ff[i-k-1-m+1+l][a[l]-96] = false;
}
}
}
for(int k=0; k<=n*m; k++)
{
if(dp[i][j][k]==0) continue;
update(dp[i+1][(j<<1)&U][k],dp[i][j][k]);
update(dp[i+1][(j<<1|1)&U][k+p],P-dp[i][j][k]);
dp[i][j][k] = 0ll;
}
}
}
for(int i=1; i<=n*m; i++)
{
llong coe = 0ll;
for(int j=1; j<=i; j++)
{
llong tmp = s*inv[j]%P*comb(i,j)%P;
if(j&1) {coe = (coe-tmp+P)%P;}
else {coe = (coe+tmp)%P;}
}
llong sum = 0ll;
for(int j=0; j<(1<<m); j++)
{
sum = (sum+dp[n][j][i])%P;
dp[n][j][i] = 0ll;
}
ans = (ans+sum*coe)%P;
}
printf("%lld\n",ans);
}
}
int main()
{
fact[0] = 1ll; for(int i=1; i<=2000000; i++) fact[i] = fact[i-1]*i%P;
finv[2000000] = quickpow(fact[2000000],P-2); for(int i=1999999; i>=0; i--) finv[i] = finv[i+1]*(i+1)%P;
for(int i=1; i<=2000000; i++) inv[i] = finv[i]*fact[i-1]%P;
cnt[0] = 0; for(int i=1; i<(1<<17); i++) cnt[i] = cnt[i>>1]+(i&1);
int T; scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m); s = 0;
for(int i=0; i<n; i++)
{
scanf("%s",str); int l = strlen(str);
for(int j=0; j<l; j++)
{
f[i][str[j]-96] = true; s++;
}
}
scanf("%s",a); bool exist = false;
for(int i=m-1; i<n; i++)
{
ok[i] = true;
for(int j=0; j<m; j++)
{
if(f[i-m+1+j][a[j]-96]==false) {ok[i] = false; break;}
}
if(ok[i]) {exist = true;}
}
if(exist==false) {printf("-1\n");}
else
{
if(n-m<=16)
{
Solution1::solve();
}
else
{
Solution2::solve();
}
}
for(int i=0; i<n; i++)
{
for(int j=1; j<=S; j++) f[i][j] = false;
ok[i] = false;
}
}
return 0;
}
UOJ #214 合唱队形 (概率期望计数、DP、Min-Max容斥)的更多相关文章
- UOJ#449. 【集训队作业2018】喂鸽子 min-max容斥,FFT
原文链接www.cnblogs.com/zhouzhendong/p/UOJ449.html 题解 设 f(i) 表示给 i 只鸽子喂食使得至少一只鸽子被喂饱的期望次数,先 min-max容斥 一下. ...
- UOJ 422 [集训队作业2018] 小Z的礼物 min-max容斥 期望 轮廓线dp
LINK:小Z的礼物 太精髓了 我重学了一遍min-max容斥 重写了一遍按位或才写这道题的. 还是期望多少时间可以全部集齐. 相当于求出 \(E(max(S))\)表示最后一个出现的期望时间. 根据 ...
- HDU5731 Solid Dominoes Tilings 状压dp+状压容斥
题意:给定n,m的矩阵,就是求稳定的骨牌完美覆盖,也就是相邻的两行或者两列都至少有一个骨牌 分析:第一步: 如果是单单求骨牌完美覆盖,请先去学基础的插头dp(其实也是基础的状压dp)骨牌覆盖 hiho ...
- codeforces 597div2 F. Daniel and Spring Cleaning(数位dp+二维容斥)
题目链接:https://codeforces.com/contest/1245/problem/F 题意:给定一个区间(L,R),a.b两个数都是属于区间内的数,求满足 a + b = a ^ b ...
- 消失之物(背包DP)(容斥或分治)
容斥做法: 首先n^2搞出f[i][j]第i个物品,j体积的方案数. 去除每个物品贡献: 设个g[i][j]表示当i不选,j体积方案数(注意不是此时的范围相对于全局,而不是1---i) 那么我们用到一 ...
- luoguP4284 [SHOI2014]概率充电器 概率期望树形DP
这是一道告诉我概率没有想象中那么难的题..... 首先,用期望的线性性质,那么答案为所有点有电的概率和 发现一个点的有电的概率来源形成了一个"或"关系,在概率中,这并不好计算... ...
- [HNOI2015]亚瑟王(概率期望,DP)
题目大意:很清晰了,不写了. $1\le T\le 444,1\le n\le 220,0\le r\le 132,0<p_i<1,0\le d_i\le 1000$. $p_i$ 和 $ ...
- Codeforces 1264C/1265E Beautiful Mirrors with queries (概率期望、DP)
题目链接 http://codeforces.com/contest/1264/problem/C 题解 吐槽:为什么我赛后看cf的题就经常1h内做出Div.1 C, 一打cf就动不动AB题不会啊-- ...
- CF1097D Makoto and a Blackboard 积性函数、概率期望、DP
传送门 比赛秒写完ABC结果不会D--最后C还fst了qwq 首先可以想到一个约数个数\(^2\)乘上\(K\)的暴力DP,但是显然会被卡 在\(10^{15}\)范围内因数最多的数是\(978217 ...
随机推荐
- bzoj4977 跳伞求生——贪心
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4977 今天讲的贪心题,真神奇啊: 首先,要得到尽量多选队友的解: 把队友按 a[i] 从小到 ...
- vue.js的第一个程序
Vue.js是一个轻巧.高性能.可组件化的MVVM库,同时拥有非常容易上手的API. 1.安装 下载 git clone https://github.com/vuejs/vue.git 页面中直接引 ...
- 在linux系统中,使用tomcat的shutdown.sh脚本停止应用,但是进程还在的解决办法
基本原理为启动tomcat时记录启动tomcat的进程id(pid),关闭时强制杀死该进程 第一步 :vi 修改tomcat下bin/catalina.sh文件,增加几行脚本,主要是记录tomcat的 ...
- 带"签名"的请求接口实现
废话少说,直接上代码(⊙﹏⊙) class Program { //签名证书 public static X509Certificate2 cerSigneCert; private static c ...
- net .异步委托知识
以前在编程中,异步用的比较少,导致C# 一些基础的 东西用法都不怎么熟悉,经常要用的时候在去查找资料比较被动,而已没真正里面理解起来,始终感觉不是自己的知识 (题外话) 首先委托关键字 Delega ...
- 6月7号shiro
Retains all Cache objects maintained by this cache manager :保留此缓存管理器维护的所有缓存对象 Destroyable可毁灭的 retain ...
- android黑科技系列——Apk混淆成中文语言代码
一.前言 最近想爆破一个app,没有加壳,简单的使用Jadx打开查看源码,结果把我逗乐了,代码中既然都是中文,而且是一些比较奇葩的中文字句,如图所示: 瞬间感觉懵逼了,这app真会玩,我们知道因为Ja ...
- VMWare 在物理机待机后,报错“该虚拟机似乎正在使用中”
在物理机待机后,刚打开虚拟机,就弹出这个画面(这种情况经常出现在远程之后,本机待机之后) 点击确定后,就弹出 当点击取消,无反应,而且再次点击VM2又弹出以上窗口,点击获取所有权,则弹出以下窗口 上网 ...
- 连接Oracle数据库帮助类
连接Oracle数据库帮助类,就是把连接Oracle数据库的方法封装起来,只需要在其它页面调用就可,不需要重复写. import java.sql.Connection; import java.sq ...
- OpenCV: OpenCV人脸检测框可信度排序
参考文章:http://blog.csdn.net/hua_007/article/details/45368607 使用OpenCV进行人脸识别时,使用 casecade.detectMultiSc ...