[六省聯考2017]分手是祝願 - 題解
阿新 • • 發佈:2019-01-13
題目連結
做法:
首先預處理出每個數的約數,用 $ 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\n",ans); return 0; }