2021牛客多校6 - Gambling Monster(分治FWT优化期望dp)
Posted Frozen_Guardian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客多校6 - Gambling Monster(分治FWT优化期望dp)相关的知识,希望对你有一定的参考价值。
题目链接:点击查看
题目大意:有一个转盘,每次转动得到 0 ∼ n − 1 0\\sim n−1 0∼n−1( n n n 是 2 的幂)的概率分别给出。最开始你有一个数 x = 0 x=0 x=0,每次转动转盘得到一个数 y y y,如果 x ⊕ y > x x\\oplus y>x x⊕y>x,就令 x = x ⊕ y x=x\\oplus y x=x⊕y,否则 x x x 不变。求使 x = n − 1 x=n-1 x=n−1,期望转动转盘的次数。
题目分析:
求期望,考虑倒着的概率 d p dp dp
设 P [ i ] P[i] P[i] 为转到 i i i 的概率,设 E [ i ] E[i] E[i] 代表当前数字为 i i i,到达 n − 1 n-1 n−1 的期望步数,显然 E [ n − 1 ] = 0 E[n-1]=0 E[n−1]=0,答案是 E [ 0 ] E[0] E[0]
设 S [ x ] S[x] S[x] 代表转动一次转盘后 x x x 发生变化的概率(即变大)的概率,不难得到 S [ x ] = ∑ x ⊕ y > x P [ y ] S[x]=\\sum\\limits_{x\\oplus y>x}P[y] S[x]=x⊕y>x∑P[y]
那么 E E E 的方程分成两个部分也不难写出: E [ x ] = ( E [ x ] + 1 ) ∗ ( 1 − S [ x ] ) + ∑ x ⊕ y = z x < z ( E [ z ] + 1 ) ∗ P [ y ] E[x]=(E[x]+1)*(1-S[x])+\\sum\\limits_{\\overset{x<z}{x\\oplus y=z}}(E[z]+1)*P[y] E[x]=(E[x]+1)∗(1−S[x])+x⊕y=zx<z∑(E[z]+1)∗P[y]
发现左右两侧都有
E
[
x
]
E[x]
E[x],所以移一下项得到:
E
[
x
]
=
(
1
−
S
[
x
]
)
+
∑
x
⊕
y
=
z
x
<
z
(
E
[
z
]
+
1
)
∗
P
[
y
]
S
[
x
]
E[x]=\\frac{(1-S[x])+\\sum\\limits_{\\overset{x<z}{x\\oplus y=z}}(E[z]+1)*P[y]}{S[x]}
E[x]=S[x](1−S[x])+x⊕y=zx<z∑(E[z]+1)∗P[y]
对于 S [ x ] S[x] S[x],我们发现只需要找到 y y y 在二进制下最高位的 1 1 1,判断一下在 x x x 在二进制下是否为 0 0 0 就可以确定是否存在贡献,这个可以 O ( n l o g n ) O(nlogn) O(nlogn) 预处理出来
对于 ∑ x ⊕ y = z x < z ( E [ z ] + 1 ) ∗ P [ y ] \\sum\\limits_{\\overset{x<z}{x\\oplus y=z}}(E[z]+1)*P[y] x⊕y=zx<z∑(E[z]+1)∗P[y],不难发现是异或卷积的形式,又因为期望 d p dp dp 是倒着推的,所以后面的答案会对前面的答案具有贡献,这个可以用 c d q cdq cdq 分治套 F W T FWT FWT 来解决
需要注意的是,在分治的过程中后面的答案会影响前面的答案,所以我们需要先递归右子区间,然后再递归左子区间
最后就是如何确定公式中
y
y
y 的取值范围呢,如果每次都是取
0
∼
n
−
1
0\\sim n-1
0∼n−1 的话肯定不行,通过分析不难发现,每次拆出来的左右区间形如:
[
x
x
x
0000
]
∼
[
x
x
x
0111
]
+
[
x
x
x
1000
]
∼
[
x
x
x
1111
]
[xxx0000]\\sim[xxx0111]+[xxx1000]\\sim[xxx1111]
[xxx0000]∼[xxx0111]+[xxx1000]∼[xxx1111]
我们上述式子中的 x x x 需要在左区间中取, z z z 需要在右区间中取,而 y y y 只需要满足 y = x ⊕ z y=x\\oplus z y=x⊕z 即可,将上面的两段区间进行异或可以得到 y ∈ [ 1000 , 1111 ] y\\in[1000,1111] y∈[1000,1111],这个每次通过位运算求解即可,不难发现 y y y 和 z z z 的区间刚好是等阶的
代码:
// Problem: Gambling Monster
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/11257/D
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
T f=1;x=0;
char ch=getchar();
while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=f;
}
template<typename T>
inline void write(T x)
{
if(x<0){x=~(x-1);putchar('-');}
if(x>9)write(x/10);
putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
const int mod=1e9+7;
int n;
LL P[N],S[N],invS[N],E[N],tmp[20],a[N],b[N];
LL q_pow(LL a,LL b) {
LL ans=1;
while(b) {
if(b&1) {
ans=ans*a%mod;
}
a=a*a%mod;
b>>=1;
}
return ans;
}
LL inv(int x) {
return q_pow(x,mod-2);
}
void FWTxor(LL *f,int x,int len)
{
for(int mid=1;(mid<<1)<=len;mid<<=1)
{
int R=mid<<1;
for(int i=0;i<len;i+=R)
for(int j=0;j<mid;j++)
{
f[i+j]=(f[i+j]+f[i+j+mid])%mod;
f[i+j+mid]=(f[i+j]-f[i+j+mid]+mod-f[i+j+mid]+mod)%mod;
f[i+j]=f[i+j]*x%mod;
f[i以上是关于2021牛客多校6 - Gambling Monster(分治FWT优化期望dp)的主要内容,如果未能解决你的问题,请参考以下文章
2021牛客多校6 - Hopping Rabbit(矩形取模+扫描线)
2021牛客多校6 - Defend Your Country(点双缩点求割点)