把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ4872】[SHOI2017] 分手是祝愿(思维+动态规划)

点此看题面

大致题意:\(n\)盏灯和\(n\)个开关,第\(i\)个开关会改变所有编号为\(i\)的约数的灯的状态。每次随机操作,直至可以在\(k\)步之内使所有灯都灭掉时采取步骤最少的方案灭掉所有灯。求灭掉所有灯的期望步数乘上\(n!\)的值。

前言

少有的我能自己挖掘性质并推出来的\(DP\)。。。感觉就是想着想着脑袋便突然开窍了。。。

转化

首先,我们考虑如何求出在某一状态下至少需要几步灭掉所有灯。

考虑我们按编号从大到小枚举每一盏灯,显然有:

  • 每个开关要么不用,要么摁一次。因为你摁得更多其实就相当于是摁了\(0\)\(1\)次,肯定不会更优。
  • 当你枚举到某一盏灯时,当且仅当它还亮着,你才能摁下开关。因为之后的灯编号比它小,肯定无法再改变它的状态,你现在的决策就相当于决定好了它最终的命运。

也就是说,我们可以很轻松地求出至少要摁几次开关(设这一次数为\(t\))。

并且根据上面第二条性质,除了这种方案以外,除非你通过摁一个开关多次来抵消自身影响,否则无论你怎么摁,都必然是非法的。

则究竟是需要摁哪几个开关其实是没必要知道的,我们只需要知道还有\(i\)个开关需要摁,则就有\(n-i\)个开关不应摁。

于是我们就可以考虑动态规划了。

动态规划

考虑我们设\(f_i\)表示从还有\(i\)个开关要摁第一次转移到还有\(i-1\)个开关要摁的状态的期望步数。

则有两种可能:选择了这\(i\)个开关中的某一个一步成功,或是选择了剩余\(n-i\)个开关中的某一个转移到还有\(i+1\)个开关的状态,那么又得花上若干步摁回来,再继续尝试摁到\(i-1\)个开关的状态。

也就是说:

\[f_i=\frac in+\frac{n-i}n(1+f_{i+1}+f_i) \]

然后我们发现方程两边都有\(f_i\),移项得到:

\[\frac inf_i=\frac in+\frac{n-i}n(1+f_{i+1}) \]

接下来显然两边同时除以\(\frac in\),得到:

\[f_i=1+\frac{n-i}i(1+f_{i+1}) \]

这样就很好\(DP\)了。

计算答案

\(t\le k\),显然可以直接\(t\)步完成。

否则,我们期望需要\(f_t\)步转移到\(t-1\)\(f_{t-1}\)步转移到\(t-2\),......,\(f_{k+1}\)步转移到\(k\)

也就是\(\sum_{i=k+1}^tf_i+k\)

具体实现详见代码。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define X 100003
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
using namespace std;
int n,k,a[N+5],f[N+5];
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
	RI i,j,Fac=1;for(scanf("%d%d",&n,&k),i=1;i<=n;++i) scanf("%d",a+i),Fac=1LL*Fac*i%X;//读入,同时计算阶乘
	RI t=0;for(i=n;i;--i) if(a[i]) for(++t,j=1;j*j<=i;++j) !(i%j)&&(a[j]^=1,j^(i/j)&&(a[i/j]^=1));//求出需要摁几次开关
	if(t<=k) return printf("%d\n",1LL*t*Fac%X),0;//如果t<=k,可以直接完成
	for(f[n]=1,i=n-1;i>k;--i) f[i]=(1LL*(n-i)*QP(i,X-2)*(f[i+1]+1)+1)%X;//动态规划
	RI ans=k;for(i=t;i>k;--i) Inc(ans,f[i]);return printf("%d\n",1LL*ans*Fac%X),0;//统计答案
}
posted @ 2020-05-25 21:03  TheLostWeak  阅读(129)  评论(0编辑  收藏  举报