\(LuckyBlock\) 良心出題人!暴力分給了 \(120pts\)html
\(T1\) 貌似是個結論題,最後知道怎麼算了,用前綴和搞了兩下,寫掛了就很草,最後只能靠暴力拿了 \(30pts\)ios
\(T2\) 顯然數論題,可是我不會化簡/kk,不過用前綴和優化了一下暴力 \(40pts\);數組
\(T3\) 依舊暴力,\(O(n^2)\) 可拿 \(40pts\)函數
\(T4\) 部分分 \(5pts\) \(+\) \(lps\) 隨機輸出 \('7'\) \(5pts\);優化
不會打暴力的 \(OIer\) 不是好 \(OIer\) ,不打暴力的都是**(沒錯說的就是CSP2020上的我ui
感受 \(LuckyBlock\) 此次考察的芝士點比較詳細,先粘個題解網址咕着,之後再補spa
改自 CF1422Chtm
發現能夠當作取出一段序列,把剩下的拼接起來blog
在拼接過程當中發現有許多部分是重複計算的,能夠用後綴和和開個 \(10^i\) 的數組預處理
算了我也說不清楚直接放代碼吧嘻嘻
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int MAXN = 2e6+6; const int INF = 1; const int mod = 1e9+7; LL hsum[MAXN], jc[MAXN]; char ch[MAXN]; LL ans; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } LL quick(LL x, LL p, LL mod){ LL res = 1; for( ; p; p >>= 1){ if(p & 1) res = res * x % mod; x = x * x % mod; } return res; } signed main() { cin>>ch; LL len = strlen(ch); int cnt = 0; cnt = 1; jc[0] = 1; for(int i = 1; i <= len; ++i){ jc[i] = jc[i - 1] * 10 % mod; } cnt = 0; for(int i = len - 1; i >= 0; --i){//求後綴數 cnt = (cnt + (ch[i] - '0') * jc[len - 1 - i] % mod) % mod; hsum[i] = cnt; // cout<<hsum[i]<<' '; } LL val = 0, sum = 0; for(int i = 0; i < len; ++i){ ans += sum * jc[len - 1 - i] % mod; ans += i * hsum[i] % mod; ans %= mod; val = (10 * val % mod + ch[i] - '0') % mod; sum = (sum + val) % mod; } printf("%lld", ans % mod); return 0; }
暴力部分核心代碼:
for(int l = 0; l < len; ++l){ LL cnt = 0; for(int r = l; r < len; ++r){ for(int i = 0; i < len; ++i){ if(i < l || i > r){ cnt = (cnt * 10 % mod + ch[i] - '0') % mod; } } ans = (ans + cnt) % mod; } }
\(40pts\) 暴力:
求 \(gcd(i, n)\) 是有屢次求的,能夠用前綴和預處理 \(2000\) 個點而後 \(O(n)\) 出結果
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1e6+6;; const int INF = 1; const int mod = 998244353; int T, l, r; int gcd[2010][2010]; int sum[2020]; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } int Gcd(int x, int y){ return x % y == 0 ? y : Gcd(y, x % y); } void init(){ for(int i = 1; i <= 2000; ++i){ for(int j = 1; j <= i; ++j){ // a[i][j] = Gcd(j, i); sum[i] = (sum[i] + Gcd(j, i)) % mod ; } } } int main() { init(); T = read(); while(T--){ l = read(), r = read(); int ans = 0; for(int i = l; i <= r; ++i){ ans = (ans + sum[i]) % mod; } printf("%d\n", ans); } return 0; }
\(100pts\) 正解
考慮化一下 \(f\) 。
考慮對於每個 \(1 \sim n\) 的值,能做爲多少數對的 \(gcd\) ,因而有:
發現 \(gcd(i, n) = d\) 的必要條件是 \(d \mid n\) ,原式能夠改成:
考慮什麼樣的 \(i\) ,知足 \(\gcd(i, n) = d\) ,顯然當且僅當 \(i = kd(k \in \mathbb{N^*})\) ,且 \(\gcd(k, \frac{n}{d}) = 1\) 是知足條件。爲保證 \(i \le n\) ,有 \(k \le \left\lfloor\frac{n}{d}\right\rfloor\) 。
因而考慮把 \(d\) 提出來,改成枚舉上述的 \(k\) ,原式等於:
考慮後面一個 \(\sum\) 的實際意義,表示 \(1 \sim \frac{n}{d}\) 中與 \(\frac{n}{d}\) 互質的個數,符合歐拉函數的定義,因而原式等於:
線性篩預處理 \(\varphi\) 後,有埃氏篩便可篩出 \(1 \sim 10^{6}\) 的全部的 \(f\) 。
作個前綴和便可回答區間詢問
複雜度 \(O(n\ \log \ n + m)\)
(Solution來自LuckyBlock的題解)
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1e6+5; const int kMax = 1e6; const int INF = 1; const int mod = 998244353; int p_cnt, p[MAXN], phi[MAXN]; int f[MAXN], sum[MAXN]; bool vis[MAXN]; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } void init(){ phi[1] = 1; for(int i = 2; i <= kMax; ++i){ if(!vis[i]){ p[++p_cnt] = i; phi[i] = i - 1; } for(int j = 1; j <= p_cnt && i * p[j] <= kMax; ++j){ vis[i * p[j]] = true; if(i % p[j] == 0){ phi[i * p[j]] = phi[i] * p[j]; break; } phi[i * p[j]] = phi[i] * (p[j] - 1); } } for(int i = 1; i <= kMax; ++i){ for(int j = i; j <= kMax; j += i){ f[j] = (f[j] + 1ll * phi[i] * (j / i) % mod) % mod; } } for(int i = 1; i <= kMax; ++i){ sum[i] = (sum[i - 1] + f[i]) % mod; } } int main() { init(); int m = read(); while(m--){ int l = read(), r = read(); printf("%d\n", (sum[r] - sum[l - 1] + mod) % mod); } }
\(40pts\) 暴力:
暴力更改區間起點暴力求全部狀況的最大值便可
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1; const int INF = 1; const int mod = 1; int n; char a[50100], b[50010]; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } int main() { n = read(); cin>>a>>b; int ans = -1; for(int i = 0; i < n; ++i){ int cnt = 0; for(int j = 0; j < n; ++j){ int x = i + j; x = (x >= n ? x - n : x); if(a[j] == '1' && b[x] == '1'){ cnt++; } } ans = max(ans, cnt); } printf("%d", ans); return 0; }
\(100pts\) 正解:
利用 bitset
容器,詳細介紹請看 Oi-Wiki
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cctype> #include<cstring> #include<string> #include<algorithm> #include<bitset> using namespace std; const int MAXN = 1e5+10; const int INF = 1; const int mod = 1; int n, ans; char s1[MAXN], s2[MAXN]; bitset <MAXN> a, b, c; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } void max(int &x, int y){if(x < y) x = y; } int main() { n = read(); scanf("%s", s1 + 1); scanf("%s", s2 + 1); for(int i = 1; i <= n; ++i){ a[i] = (s1[i] == '1'); b[i] = (s2[i] == '1'); } for(int i = 1; i <= n; ++i){ b[n + 1] = b[1]; b >>= 1; max(ans, (a & b).count()); } printf("%d", ans); return 0; }
改自 CF1422C
只拿了部分分就不粘碼了嘻嘻