Loading

「六省联考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}{恐怖奴隶主黄晨衍是个超级大毒瘤!}\)

posted @ 2020-10-29 20:39  SmilingKnight  阅读(117)  评论(0编辑  收藏  举报