以后不准備把打的每一場比賽的題解都掛在 cnblogs 上了因為我懶。
但這次還是想寫寫。
A
顯然,當 \(n < 42\) 時輸出 AGC+str(n)
;否則,輸出 AGC+str(n+1)
。時間復雜度為 \(O(1)\)。
注意需要補足 \(3\) 位。
代碼:
#include <stdio.h>
int main(){
int n;
scanf("%d", &n);
if (n < 10){
printf("AGC00%d", n);
} else if (n < 42){
printf("AGC0%d", n);
} else {
printf("AGC0%d", n + 1);
}
return 0;
}
B
直接暴力枚舉是否匹配即可。時間復雜度為 \(O(nM)\)。
代碼:
#include <stdio.h>
#include <string.h>
const int N = 10 + 7, M = 3e5;
char s[N], t[M + 7];
int main(){
int n;
scanf("%s", &s[1]);
n = strlen(&s[1]);
for (int i = 1; i <= M; ){
t[i++] = 'o';
t[i++] = 'x';
t[i++] = 'x';
}
for (int i = 1; i + n - 1 <= M; i++){
bool flag = true;
for (int j = 1; j <= n; j++){
if (s[j] != t[i + j - 1]){
flag = false;
break;
}
}
if (flag){
printf("Yes");
return 0;
}
}
printf("No");
return 0;
}
C
對於每一個位置 \((i, j)\),顯然當 \(i - a = j - b\) 或 \(i - a = b - j\) 時為黑色。
暴力枚舉即可。時間復雜度為 \(O(q - p)(s - r)\)。
代碼:
#include <stdio.h>
typedef long long ll;
int main(){
ll n, a, b, p, q, r, s;
scanf("%lld %lld %lld", &n, &a, &b);
scanf("%lld %lld %lld %lld", &p, &q, &r, &s);
for (ll i = p; i <= q; i++){
for (ll j = r; j <= s; j++){
if (i - a == j - b || i - a == b - j){
printf("#");
} else {
printf(".");
}
}
printf("\n");
}
return 0;
}
D
顯然是一個線段覆蓋問題。排序后貪心即可。時間復雜度為 \(O(n \log n)\)。
代碼:
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct {
int l;
int r;
} Wall;
Wall wall[200007];
bool operator <(const Wall a, const Wall b){
if (a.r != b.r) return a.r < b.r;
return a.l < b.l;
}
int main(){
int n, d, ans = 0;
cin >> n >> d;
for (int i = 1; i <= n; i++){
cin >> wall[i].l >> wall[i].r;
}
sort(wall + 1, wall + n + 1);
for (int i = 1, j = 0x80000000; i <= n; i++){
if (wall[i].l > j + d - 1){
j = wall[i].r;
ans++;
}
}
cout << ans;
return 0;
}
E
顯然是一個數論分塊怎么直接出板子。時間復雜度為 \(O(\sqrt{n})\)。
代碼:
#include <stdio.h>
typedef long long ll;
int main(){
ll n, ans = 0;
scanf("%lld", &n);
for (register ll i = 1, j; i <= n; i = j + 1){
ll tn = n / i;
j = n / tn;
ans += tn * (j - i + 1);
}
printf("%lld", ans);
return 0;
}
F
如果不存在相同的前綴和,顯然可以設 \(dp_i\) 表示前 \(i\) 位可以組成的方案數,則 \(dp_i = 2dp_{i - 1} + 1\)。
現在考慮加入相同的前綴和。設 \(pos\) 表示上一個出現當前前綴和的位置,賽后根據樣例找規律得出減去 \(dp_{pos - 1}\) + 1 即可。
考慮到 \(1 \sim n\) 整體的前綴和重復沒有意義,答案為 \(dp_{n - 1} + 1\)。時間復雜度為 \(O(n \log n)\)。
代碼:
#include <iostream>
#include <map>
using namespace std;
typedef long long ll;
const int mod = 998244353;
int dp[200007];
ll sum[200007];
map<ll, int> mp;
int main(){
int n;
cin >> n;
for (int i = 1; i <= n; i++){
int a;
cin >> a;
sum[i] = sum[i - 1] + a;
}
for (int i = 1; i < n; i++){
if (!mp.count(sum[i])){
dp[i] = (dp[i - 1] * 2 % mod + 1) % mod;
} else {
dp[i] = ((dp[i - 1] * 2 % mod - dp[mp[sum[i]] - 1]) % mod + mod) % mod;
}
mp[sum[i]] = i;
}
cout << (dp[n - 1] + 1) % mod;
return 0;
}
G
前置芝士:莫比烏斯反演
講一種比較麻煩的做法。
式子就不推了,反正容斥后推起來也很簡單。結果為 \(\frac{\displaystyle\sum_{i = 1}^n \mu(i) \sum_{j = 1}^n \mu(j) (\sum_{i \mid k}^n [j \mid p_k])^2 + n^2 - 2(\sum_{i = 1}^n \varphi(i) - 1) + n - 1}{2}\)。
考慮枚舉 \(i\)、所有可能的 \(k\) 及 \(P_k\) 的因數並用打了時間戳的數組維護后面那個 \(\sum\) 的值即可。時間復雜度為 \(O(n \sqrt{n} \ln n)\)。
賽后看了一下大家的代碼,發現直接暴力可過。我賽時居然還寫了樹狀數組。我真是個 zz。
代碼:
#include <stdio.h>
#include <math.h>
typedef long long ll;
const int N = 2e5 + 7;
int prime[N], phi[N], mu[N], P[N], tm[N], val[N];
ll sum[N];
bool p[N];
inline void init(int n){
int cnt = 0;
p[0] = p[1] = true;
phi[1] = 1;
mu[1] = 1;
for (register int i = 2; i <= n; i++){
if (!p[i]){
prime[++cnt] = i;
phi[i] = i - 1;
mu[i] = -1;
}
for (register int j = 1; j <= cnt && i * prime[j] <= n; j++){
int t = i * prime[j];
p[t] = true;
if (i % prime[j] == 0){
phi[t] = phi[i] * prime[j];
mu[t] = 0;
break;
}
phi[t] = phi[i] * (prime[j] - 1);
mu[t] = -mu[i];
}
}
for (register int i = 1; i <= n; i++){
sum[i] = sum[i - 1] + phi[i];
}
}
int main(){
int n;
ll ans;
scanf("%d", &n);
init(n);
ans = (ll)n * n - (sum[n] * 2 - 1) * 2 + (n - 1);
for (register int i = 1; i <= n; i++){
scanf("%d", &P[i]);
}
for (register int i = 1; i <= n; i++){
for (register int j = i; j <= n; j += i){
int t = sqrt(P[j]);
for (register int k = 1; k <= t; k++){
if (P[j] % k == 0){
if (mu[k] != 0){
if (tm[k] != i){
tm[k] = i;
val[k] = 0;
}
ans += mu[i] * mu[k] * ((val[k]++) * 2 + 1);
}
if (k * k != P[j]){
int tp = P[j] / k;
if (mu[tp] != 0){
if (tm[tp] != i){
tm[tp] = i;
val[tp] = 0;
}
ans += mu[i] * mu[tp] * ((val[tp]++) * 2 + 1);
}
}
}
}
}
}
printf("%lld", ans / 2);
return 0;
}