Problem
Solution
感觉dp状态的设置好巧妙啊
首先要明确的是怎么计算最小步数。就是直接从n到1扫,如果有亮着的,就按这个开关,模拟一下是
的
设f[i]表示在局面的最小步数为i时,转移到最少步数为i-1时的期望花费。只要是相应的灯,按的次序是不会影响答案的,那么i次就说明还需要按i个灯,则有i/n的概率到下一步,而有(n-i)/n的概率回到f[i+1]状态,则有
再移项即得
然后这是一个差分序列,求和即可得到ans
Code
#include <cstdio>
#define rg register
using namespace std;
typedef long long ll;
const int maxn=100010,mod=100003;
struct data{int v,nxt;}edge[maxn*20];
int n,k,p,cnt,ans,fac=1,head[maxn],a[maxn],f[maxn],inv[maxn];
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
inline int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline void insert(int u,int v){edge[++p]=(data){v,head[u]};head[u]=p;}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
read(n);read(k);
inv[0]=inv[1]=1;f[n]=1;
for(rg int i=1;i<=n;i++)
{
read(a[i]);fac=(ll)fac*i%mod;
for(rg int j=i;j<=n;j+=i) insert(j,i);
if(i^1) inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
}
for(rg int i=n;i;i--)
if(a[i])
{
cnt++;
for(int j=head[i];j;j=edge[j].nxt) a[edge[j].v]^=1;
}
if(cnt<=k){printf("%lld\n",(ll)cnt*fac%mod);return 0;}
for(rg int i=n-1;i>k;i--) f[i]=((ll)(n-i)*f[i+1]+n)%mod*inv[i]%mod;
for(rg int i=cnt;i>k;i--) ans=pls(ans,f[i]);
printf("%lld\n",(ll)(ans+k)*fac%mod);
return 0;
}