[六省联考2017]分手是祝愿
链接:https://www.luogu.com.cn/problem/P3750
题目描述:有\(n\)个灯,每个灯有一个开关,每一次操作一个灯会影响其约数的灯。若能小于等于\(k\)次成功将所有灯关闭则使用这张方法,否则随机操作,求期望步数\(\times n!\)。
题解:我们贪心的关灯一定时从右往左扫着关,那么就可以处理出哪些灯要关,令它们有\(K\)个,对于随机关灯的情况,我们即要求随机开关等使得恰好将要关的灯中\(K-k\)个关奇数次的期望步数。
令\(dp_{i}\)表示\(i\)个灯的期望步数,那么\(dp_{i}=dp_{i-1}\times i+dp_{i+1}\times (n-i)\)。
可将其化为\(dp_{i+1}=\frac{dp_{i}-dp_{i-1}\times i}{n-i}\)的形式。
然后因\(dp_{k}=0\)已知,那么可令\(dp_{i}=a_{i}\times dp_{k+1}+b_{i}\),转移\(a_{i},b_{i}\),然后可将\(dp_{k+1}\)解方程接触,这样就可以求出\(dp_{K}\)了。
#include<iostream>
#include<cstdio>
#define mod 100003
using namespace std;
long long n,k,K,a[100001],dp[100001],fac[100001],dp2[100001];
int read()
{
char c=0;
int sum=0;
while (c<'0'||c>'9')
c=getchar();
while ('0'<=c&&c<='9')
{
sum=sum*10+c-'0';
c=getchar();
}
return sum;
}
long long fast_pow(long long a,int b)
{
if (b==0)
return 1;
if (b&1)
return fast_pow(a*a%mod,b/2)*a%mod;
else
return fast_pow(a*a%mod,b/2);
}
int main()
{
n=read(),k=read();
for (int i=1;i<=n;++i)
a[i]=read();
for (int i=n;i>=1;--i)
{
if (a[i]==1)
{
K++;
for (int j=1;j*j<=i;++j)
if (i%j==0)
{
a[j]^=1;
if (j*j!=i)
a[i/j]^=1;
}
}
}
fac[0]=1;
for (int i=1;i<=n;++i)
fac[i]=fac[i-1]*i%mod;
dp[k]=0,dp2[k+1]=1;
for (int i=k+2;i<=n;++i)
{
dp[i]=(n*dp[i-1]%mod-n-dp[i-2]*(i-1)%mod)%mod*fast_pow(n-i+1,mod-2)%mod;
dp2[i]=(n*dp2[i-1]%mod-dp2[i-2]*(i-1)%mod)%mod*fast_pow(n-i+1,mod-2)%mod;
}
dp[k+1]=(dp[n-1]+1-dp[n])*fast_pow(dp2[n]-dp2[n-1],mod-2)%mod;
for (int i=k+2;i<=n;++i)
dp[i]=(n*dp[i-1]%mod-n-dp[i-2]*(i-1)%mod)%mod*fast_pow(n-i+1,mod-2)%mod;
printf("%lld\n",((dp[K]+min(k,K))*fac[n]%mod+mod)%mod);
return 0;
}
本文来自博客园,作者:zhouhuanyi,转载请注明原文链接:https://www.cnblogs.com/zhouhuanyi/p/16983755.html

浙公网安备 33010602011771号