传送门
一道不错的题。
考虑
n
=
=
k
n==k
n==k的时候怎么做。
显然应该从
n
n
n到
1
1
1如果灯是开着的就把它关掉这样是最优的。
不然如果乱关的话会互相影响肯定不如这种优。
于是就可以定义状态
f
[
i
]
f[i]
f[i]表示从当前按
i
i
i盏为最优方案转移到按
i
−
1
i-1
i−1盏为最优方案的代价。
然后
f
[
i
]
=
i
n
+
n
−
i
n
∗
(
1
+
f
[
i
]
+
f
[
i
+
1
]
)
f[i]=\frac i n+\frac {n-i} n*(1+f[i]+f[i+1])
f[i]=ni+nn−i∗(1+f[i]+f[i+1])
移项解方程可以推出最后的式子:
f
[
i
]
=
i
n
∗
(
n
+
(
n
−
i
)
∗
f
[
i
+
1
]
)
f[i]=\frac i n*(n+(n-i)*f[i+1])
f[i]=ni∗(n+(n−i)∗f[i+1])
代码:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
typedef long long ll;
const int N=1e5+5,mod=1e5+3;
int n,k,inv[N],a[N],f[N],ans=0,cnt=0;
int main(){
n=read(),k=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=n;i;--i)if(a[i]){
++cnt;
for(int j=1;j*j<=i;++j){
if(i!=i/j*j)continue;
a[j]^=1,a[i/j]^=(i/j!=j);
}
}
if(cnt<=k){
for(int i=2;i<=n;++i)cnt=(ll)cnt*i%mod;
cout<<cnt;
return 0;
}
inv[1]=1;
for(int i=2;i<=n;++i)inv[i]=(ll)inv[mod%i]*(mod-mod/i)%mod;
f[n]=1;
for(int i=n-1;i>k;--i)f[i]=(ll)inv[i]*((((ll)n+(ll)(n-i)*f[i+1]%mod))%mod)%mod;
for(int i=cnt;i>k;--i){
ans+=f[i];
if(ans>=mod)ans-=mod;
}
ans+=k;
if(ans>=mod)ans-=mod;
for(int i=2;i<=n;++i)ans=(ll)ans*i%mod;
cout<<ans;
return 0;
}