题解 [XXI Open Cup H] Harsh Comments

传送门
[PKUWC2018]猎人杀

一开始的想法是计算出每个 \(A_i\) 在最后面的概率,再算出每个 \(B_i\) 在这个 \(A_i\) 后面的概率
然后发现各种不独立
于是换成对每个 \(B_i\),计算其在所有 \(A_i\) 之后被删除的概率
以为可以对每对 \((A_i, b)\) 计算概率再乘起来,然后发现又不独立
原因是满足一对 \((A_i, b)\) 后合法方案就不是全集了

然后爬去康题解
发现这个东西可以容斥求
钦定 \(s\) 集合中的 \(A\)\(b\) 后选的概率是 \(\frac{b}{b+\sum a_i}\)
那么容斥式子应该是

\[\sum\limits_s(-1)^{|s|}\frac{b}{b+\sum\limits_{i\in s}a_i} \]

又发现题目保证了 \(\sum a\leqslant 1e4\)
所以可以背包求 \(\sum a_i=j\)\(s\) 的容斥系数之和
然后发现各种不对
魔改成

\[\sum\limits_{s\neq \varnothing}(-1)^{|s|-1}\frac{b}{b+\sum\limits_{i\in s}a_i} \]

发现对了
然后不懂为啥
折腾了半天才发现我想要的不是所有 \(A\) 在 b 之前被删的概率,而是 \(b\) 在至少一个 \(A\) 前被删的概率……
复杂度 \(O(懒得算)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
const ll mod=998244353;
ll a[N], b[N], f[N], ans;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

signed main()
{
	n=read(); m=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	for (int i=1; i<=m; ++i) b[i]=read();
	f[0]=-1;
	int sum=0;
	for (int i=1; i<=n; ++i) {
		sum+=a[i];
		for (int j=sum; j>=a[i]; --j) f[j]=(f[j]-f[j-a[i]])%mod;
	}
	for (int i=1; i<=m; ++i)
		for (int j=1; j<=sum; ++j)
			ans=(ans+f[j]*b[i]%mod*qpow(b[i]+j, mod-2))%mod;
	// int lim=1<<n;
	// for (int i=1; i<=m; ++i) {
	// 	for (int s=1; s<lim; ++s) {
	// 		int sum=0;
	// 		for (int j=1; j<=n; ++j) if (s&(1<<j-1)) sum+=a[j];
	// 		ans=(ans+(__builtin_popcount(s)&1?1:-1)*b[i]*qpow(b[i]+sum, mod-2))%mod;
	// 	}
	// }
	printf("%lld\n", ((ans+n)%mod+mod)%mod);
	
	return 0;
}
posted @ 2022-06-02 15:48  Administrator-09  阅读(1)  评论(0编辑  收藏  举报