传送门
文章目录
- 解析
- 代码
解析
首先,开关开关两次等于没动,所有对于一个解来说,开关的状态只有开与不开之分
接下来的一个关键点是:每一个开关的效果无法被其他开关操作的组合代替
所以这个题应该只有唯一解
那么我们可以不计代价,只要考虑怎么搞出这个解就行了
因为一个开关只能影响因数,所以从大到小考虑遇见亮的灯无脑关就一定可以完成任务
既然唯一解,那么这个解就是它了
那么我们找出了这个解需要的操作数,记为cnt
那么显然的是,cnt<=k时,期望就是cnt
接下来考虑cnt>k的情况
设计dp:
f[i]表示**从剩i个灯要操作转移到(i-1)个灯要操作的期望步数
考虑下一步,有i/n的概率选到对的灯,(n-i)/n的概率选错,需要回到(i+1)的状态
那么可以得到
fi=i/n∗1+(n−i)/n∗(f[i+1]+fi+1)f_i=i/n*1+(n-i)/n*(f[i+1]+f_i+1)fi=i/n∗1+(n−i)/n∗(f[i+1]+fi+1)
移项整理一下,得到:
fi=(n+(n−i)∗f[i+1])/if_i=(n+(n-i)*f[i+1])/ifi=(n+(n−i)∗f[i+1])/i
统计答案从fk+1加到fcnt即可
最后再+k
不要忘了阶乘!
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+100;
const int mod=100003;
ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;
}
int n,m,k,cnt;
int op[N];
ll f[N];
void work(int x){int top=floor(sqrt(x));for(int i=1;i<=top;i++){if(x%i==0){op[i]^=1;if(x/i!=i) op[x/i]^=1;}}
}
void Mod(double &x){x-=mod*(floor(x/mod));
}
ll ksm(ll x,int k){ll res=1;while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}
int main(){n=read();k=read();for(int i=1;i<=n;i++) op[i]=read();for(int i=n;i>=1;i--){if(op[i]){work(i);cnt++;}}f[n]=1;for(int i=n-1;i>k;i--){f[i]=(n+1ll*(n-i)*f[i+1]%mod)*ksm(i,mod-2)%mod;//Mod(f[i]);}ll res=0;if(cnt<=k) res=cnt;else{for(int i=cnt;i>k;i--){res=(res+f[i])%mod; }res+=k;}for(int i=1;i<=n;i++){res=res*i%mod;//assert(jc>=0);}printf("%lld",res);
}
/*
3
1 3 4 5
1 4 7 3
9 3 2 2
*/