【BZOJ4872】分手是祝願(動態規劃,數學期望)
阿新 • • 發佈:2018-02-06
esp math map ostream pac mes ++i rac define
\[f[x]=\frac{x}{n}(f[x-1]+1)+\frac{n-x}{n}(f[x+1]+1)\]
也就是
\[f[x]=\frac{x}{n}f[x-1]+\frac{n-x}{n}f[x+1]+1\]
【BZOJ4872】分手是祝願(動態規劃,數學期望)
題面
BZOJ
題解
對於一個狀態,如何求解當前的最短步數?
從大到小枚舉,每次把最大的沒有關掉的燈關掉
暴力枚舉因數關就好
假設我們知道了當前至少要關\(tot\)次
如果一個燈被動兩次以上是沒有任何意義的
所以,相當於,要動的燈只有\(tot\)個
其他的是沒有任何意義的
所以,題面可以變為:
現在有\(tot\)個\(1\),\(n-tot\)個\(0\)
每次隨機選擇一個數將其異或\(1\)
求最終變為\(0\)的期望
我們現在考慮一下
設\(f[x]\)為剩下\(x\)個\(1\)的期望
並且我們知道了所有的值,
那麽,我們不難推出:
也就是
\[f[x]=\frac{x}{n}f[x-1]+\frac{n-x}{n}f[x+1]+1\]
同時,我們有邊界:
\(f[x]=x(x\leq K)\)
\(f[n]=f[n-1]+1\)
如果考慮把\(f[n]\)帶入到\(f[n-1]\)的式子中
我們可以得到只有\(f[n-1],f[n-2]\)之間的關系式
如此遞推下去就可以推出\(f[K+1]\)和\(f[K]\)的關系式
這樣就是常數項了
回朔帶回去就可以求解
時間復雜度\(O(nlogn)\)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 120000
#define MOD 100003
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
int tot,n,K;
int a[MAX],ans[MAX];
int inv[MAX];
int DFS(int x,int ss)
{
if(x<=K)return ans[x]=x;
ss=(1ll*n*inv[x]%MOD+1ll*ss*(n-x)%MOD*inv[x]%MOD)%MOD;
return ans[x]=(DFS(x-1,ss)+ss)%MOD;
}
int main()
{
n=read();K=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=n;i;--i)
if(a[i])
{
for(int j=1;j*j<=i;++j)
if(i%j==0)
{
a[j]^=1;
if(j*j!=i)a[i/j]^=1;
}
++tot;
}
if(tot<=K)
{
for(int i=1;i<=n;++i)tot=1ll*tot*i%MOD;
printf("%d\n",tot);
return 0;
}
for(int i=1;i<=n;++i)inv[i]=fpow(i,MOD-2);
DFS(n,1);
for(int i=1;i<=n;++i)ans[tot]=1ll*ans[tot]*i%MOD;
printf("%d\n",ans[tot]);
return 0;
}
【BZOJ4872】分手是祝願(動態規劃,數學期望)