「六省联考2017」分手是祝愿
「六省联考2017」分手是祝愿
由于熄灭一盏编号较大的灯后受影响的必定是编号较小的灯,所以熄灯的关系是一张\(\operatorname{DAG}\).
定义能够影响灯\(i\)的开关的编号集合为\(L_i\),开关\(i\)能够影响的灯的编号集合为\(R_i\).
假设现在有一盏亮着的灯编号为\(i\),如果我们想在不改变其他灯\(x\in L_i\)的状态,那么我们唯一的做法就是按下开关\(i\).
那么最后被按下的开关集合其实是确定的,所以我们可以按编号从大到小判断每一个开关是否需要按下。
定义状态\(i\)表示当前状态下还有\(i\)个开关需要按下,即一共有\(i\)个开关应该按却还没按,或是不该按却按了。
设\(f_i\)表示从状态\(i\)到状态\(i-1\)的期望操作数。
每次操作时,有\(\cfrac{i}{n}\)的概率按下一个需要被按的开关,有\(\cfrac{n-i}{n}\)的概率按下一个不需要被按的开关,由此可以得出转移方程:
\[f_i=\frac{n-i}{n}\times(f_{i+1}+f_i)+1\\
\]
化简该方程可得递推式:
\[\begin{align*}
nf_i&=n+(n-i)\times(f_{i+1}+f_i)\\
if_i&=n+(n-i)\times f_{i+1}\\
f_i&=\frac{(n-i)\times f_{i+1}+n}{i}
\end{align*}
\]
假设有\(m\)个开关需要被按下,那么到达状态k的期望操作数为\(\sum_{i=k+1}^{m}f_i\).
将该式结果加上\(k\)即是将\(m\)个开关全部按下的期望操作数。
#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
const int mod=100003;
int n,k,a[maxn],now,f[maxn],ans;
inline int read(){
int res=0,f_f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f_f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=(res<<3)+(res<<1)+(ch-'0'),ch=getchar();
return res*f_f;
}
inline int fpow(int x,int y){
int res=1;
while(y){
if(y&1) res=1ll*res*x%mod;
x=1ll*x*x%mod,y>>=1;
}
return res;
}
int main(){
n=read(),k=read(),ans=k;
for (int i=1;i<=n;i++) a[i]=read();
for (int i=n;i;i--){
for (int j=i+i;j<=n;j+=i) a[i]^=a[j];
if(a[i]) now++;
}
if(now<=k){
for (int i=1;i<=n;i++) now=1ll*now*i%mod;
printf("%d\n",now);
return 0;
}
f[n]=1;
for (int i=n-1;i;i--){
f[i]=(1ll*(n-i)*f[i+1]%mod+n)%mod*fpow(i,mod-2)%mod;
}
for (int i=k+1;i<=now;i++) ans=(ans+f[i])%mod;
for (int i=1;i<=n;i++) ans=1ll*ans*i%mod;
printf("%d\n",ans);
return 0;
}
\(\color{white}{恐怖奴隶主黄晨衍是个超级大毒瘤!}\)