[SHOI 2017] 分手是祝願
阿新 • • 發佈:2019-03-29
多個 getchar() push typedef -- 簡單 復雜度 轉移 開關
[題目鏈接]
https://www.lydsy.com/JudgeOnline/problem.php?id=4872
[算法]
首先發現 , 對於一個開關 , 按下2次和沒按是等價的 , 因此每個開關最多按一次
考慮k = n的情況 , 只需簡單倒序貪心即可
考慮隨機的情況 , 由觀察可知一個開關不能由多個開關組合得到
用fi表示i次將所有開關變關到(i - 1)次將所有開關變關的期望步數
有轉移方程fi = i / n + (1 - i / n) * (1 + fi + 1 + fi)
將該轉移方程看作一個一元一次方程 , 即可解出fi
不再贅述 , 詳見代碼
時間復雜度 : O(N)
[代碼]
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int P = 100003; const int N = 100010; int n , k , cnt; int a[N] , inv[N] , dp[N]; vector< int > D[N]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if(c == ‘-‘) f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - ‘0‘; x *= f; } int main() { read(n); read(k); for (int i = 1; i <= n; ++i) read(a[i]); inv[1] = 1; for (int i = 2; i <= n; ++i) inv[i] = 1ll * (P - P / i) * inv[P % i] % P; for (int i = 1; i <= n; ++i) { for (int j = i; j <= n; j += i) { D[j].push_back(i); } } for (int i = n; i >= 1; --i) { if (a[i]) { for (unsigned j = 0; j < D[i].size(); ++j) a[D[i][j]] ^= true; ++cnt; } } int ans = 0; if (cnt <= k) ans = cnt; else { dp[n] = 1; for (int i = n - 1; i >= 1; --i) dp[i] = (1ll * dp[i + 1] * (n - i) % P * inv[i] % P + 1ll * n * inv[i] % P) % P; for (int i = cnt; i > k; --i) ans = (ans + dp[i]) % P; ans = (ans + k) % P; } for (int i = 1; i <= n; ++i) ans = 1ll * ans * i % P; printf("%d\n" , ans); return 0; }
[SHOI 2017] 分手是祝願