题目链接
做法:
首先预处理出每个数的约数,用 $ vector $ 存,时间是调和级数 $ O(n log n) $ 。
部分分:当 $ n = k $ 时,每次操作最优,然后从右往左枚举,若果当前为1则用掉一次,暴力修改。得 $ 50 $ 分。
正解: $ f[i] $ 表示对于 $ n $ 盏灯,从需要按 $ i $ 次能全部熄灭到按 $ i - 1 $ 次能全部熄灭的期望。得
f[i] = i * inv[n] + (n - i) * inv[n] * (f[i] + f[i+1] + 1)
移项得
f[i] = (f[i+1] * (n - i) + n) * inv[i];
从 $ n $ 倒推。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=100003;
const int N=100010;
int n,k,tot;
int a[N];
vector <int> d[N];
ll f[N],inv[N],ans=0;
void init() {
for(int i=1;i<=n;i++) for(int j=i;j<=n;j+=i) d[j].push_back(i);
}
int main() {
scanf("%d%d",&n,&k),init();
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(int i=n;i>=1;i--)
if(a[i]) {
++tot; for(int j=0;j<d[i].size();j++) a[d[i][j]]^=1;
}
f[n]=1;
for(int i=n-1;i>k;i--) f[i]=(n%mod+(n-i)%mod*f[i+1]%mod)%mod*inv[i]%mod;
for(int i=k;i;i--) f[i]=1;
for(int i=1;i<=tot;i++) ans=(ans+f[i])%mod;
for(int i=2;i<=n;i++) ans=ans*i%mod;
printf("%lld
",ans);
return 0;
}