Loading

[六省联考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;
}
posted @ 2022-12-14 21:58  zhouhuanyi  阅读(31)  评论(0)    收藏  举报