首先考虑k=n的话最优解是怎样的。
因为拉一盏灯只会影响到比它标号小的灯和自己。
所以我们按标号从大到小考虑。如果一盏灯还亮着就必须拉,并且把影响到的灯改变。这样就可以得到目前状态的最小操作次数了。
设f[i]表示剩余最小操作次数为i时还期望操作多少步,可以列出方程:
f[i]=in∗f[i−1]+n−in∗f[i+1]+1
f
[
i
]
=
i
n
∗
f
[
i
−
1
]
+
n
−
i
n
∗
f
[
i
+
1
]
+
1
特别的对于i<=k,f[i]=i,f[n]=f[n-1]+1.
可以高斯消元
O(n3)
O
(
n
3
)
考虑进一步优化,原方程变一变可以得到
f[i]−f[i−1]=n−in(f[i+1]−f[i−1])+1
f
[
i
]
−
f
[
i
−
1
]
=
n
−
i
n
(
f
[
i
+
1
]
−
f
[
i
−
1
]
)
+
1
我们对f数组差分一下,令g[i]=f[i]-f[i-1]。
那么有
g[i]=n−in(g[i+1]+g[i])+1
g
[
i
]
=
n
−
i
n
(
g
[
i
+
1
]
+
g
[
i
]
)
+
1
g[i]=((n−i)g[i+1]+n)/i
g
[
i
]
=
(
(
n
−
i
)
g
[
i
+
1
]
+
n
)
/
i
可以递推了,特别的
g[n]=1,g[i]=1,i<=k
g
[
n
]
=
1
,
g
[
i
]
=
1
,
i
<=
k
复杂度
O(nn−−√)
O
(
n
n
)
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
#define mod 100003
inline char gc(){
static char buf[1<<16],*S,*T;
if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,k,g[N],inv[N],ans=1,a[N];
inline void inc(int &x,int y){x+=y;x%=mod;}
int main(){
// freopen("a.in","r",stdin);
n=read();k=read();inv[1]=1;
for(int i=2;i<=n;++i) inv[i]=(ll)inv[mod%i]*(mod-mod/i)%mod;
int m=0;for(int i=1;i<=n;++i) a[i]=read(),ans=(ll)ans*i%mod;
for(int i=n;i>=1;--i){
if(!a[i]) continue;++m;
for(int x=1;x*x<=i;++x){
if(i%x) continue;a[x]^=1;
if(x*x!=i) a[i/x]^=1;
}
}if(m<=k){ans=(ll)ans*m%mod;printf("%d\n",ans);return 0;}
g[n]=1;
for(int i=n-1;i>k;--i)
g[i]=((ll)(n-i)*g[i+1]+n)%mod*inv[i]%mod;
for(int i=1;i<=k;++i) g[i]=1;
for(int i=1;i<=m;++i) inc(g[i],g[i-1]);
ans=(ll)g[m]*ans%mod;
printf("%d\n",ans);
return 0;
}