Codeforces Round #788 (Div. 2) VP 記錄
蛤蛤我就是那個 VP 只過三題的垃圾。
D 據說可以 OEIS,然後因為讀錯題寄了半小時,OEIS 又翻了半小時沒找到。最後幾分鐘才發現是個傻逼規律。
E 也不是很難,何隊一眼秒了。
A. Prof. Slim
發現只能交換正負號。那就把所有負號放在前面看看是不是一個不降序列即可。
#include<bits/stdc++.h> #define LL long long //#define int long long #define orz cout << "tyy YYDS!!!\n" using namespace std; const int MAXN = 2e5 + 10; const int INF = 1e9 + 7; const int mod = 998244353; int read() { int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return f ? -s : s; } void Main() { int n = read(); vector<int> a(n + 1); int cnt = 0; for(int i = 1; i <= n; ++i) { a[i] = read(); cnt += a[i] < 0; } for(int i = 1; i <= n; ++i) { if(i <= cnt) a[i] = - abs(a[i]); else a[i] = abs(a[i]); } for(int i = 2; i <= n; ++i) { if(a[i] < a[i - 1]) { return puts("NO"), void(); } } puts("YES"); } signed main() { int T = read(); while(T--) Main(); return 0; }
B. Dorms War
標記一下特殊點。
從前往後列舉每一個字元。
隨便用一個值 \(sc\) 來維護這個特殊點以及因為在他前面而被刪掉的點。
因此記錄一下上一個特殊點的位置 \(lst\)。
設當前列舉到的 \(i\) 為特殊點。
那麼因為在這個點前面而被刪掉的點有 \(\max (0, sc - 2len) + len\) 個,其中 \(len = i - lst\)。
就是考慮這兩個特殊點同時刪,後面這個特殊點刪到第 \(len\) 次的時候就把前面那個特殊點刪掉了,此時前面那個特殊點也刪了 \(len\) 次,那麼剩下的就可以讓當前這個特殊點刪了。
#include<bits/stdc++.h> #define LL long long //#define int long long #define orz cout << "tyy YYDS!!!\n" using namespace std; const int MAXN = 2e5 + 10; const int INF = 1e9 + 7; const int mod = 998244353; int read() { int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return f ? -s : s; } int n, K, lst; char s[MAXN]; char t[30]; bool vis[30]; int stc[MAXN], sc = 0; void Main() { n = read(), sc = lst = 0; cin >> s + 1; K = read(); memset(vis, false, sizeof vis); for(int i = 1; i <= K; ++i) scanf("%c", &t[i]), getchar(), vis[t[i] - 'a'] = true; // for(int i = 1; i <= K; ++i) cout << t[i] << " "; puts(""); // cout << "check: " << vis['y' - 'a'] << "\n"; while(n && !vis[s[n] - 'a']) --n; for(int i = 1; i <= n; ++i) { int c = s[i] - 'a'; if(!vis[c]) { ++sc; } else { if(lst) { int len = i - lst; sc = max(0, sc - 2 * len) + len; } lst = i; ++sc; } } sc = max(sc - 1, 0); cout << sc << "\n"; // cout << "ans: " << n << " " << sc << "\n"; } signed main() { int T = read(); while(T--) Main(); return 0; }
C. Where is the Pizza?
看到兩個排列,果斷考慮轉化成圖論。
將 \(a_i\) 和 \(b_i\) 連邊。
最終的情況一定是若干個環。
發現只要確定了環上的一個點,剩下的都能確定。
也就是說,如果一個環上的點數 \(>2\) 且沒有已經確定的點,那麼這個環會對方案數貢獻一個 \(\times 2\) 。
#include<bits/stdc++.h> #define LL long long //#define int long long #define orz cout << "tyy YYDS!!!\n" using namespace std; const int MAXN = 2e5 + 10; const int INF = 1e9 + 7; const int mod = 1e9 + 7; int read() { int s = 0, f = 0; char ch = getchar(); while(!isdigit(ch)) f |= (ch == '-'), ch = getchar(); while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar(); return f ? -s : s; } int fa[MAXN]; int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); } void Main() { int n = read(); vector<int> a(n + 1), b(n + 1), d(n + 1), siz(n + 1); vector<int> vis(n + 1, 0); for(int i = 1; i <= n; ++i) a[i] = read(); for(int i = 1; i <= n; ++i) b[i] = read(); for(int i = 1; i <= n; ++i) d[i] = read(); for(int i = 1; i <= n; ++i) fa[i] = i, siz[i] = 1; for(int i = 1; i <= n; ++i) { int uf = find(a[i]), vf = find(b[i]); if(uf != vf) fa[uf] = vf, siz[vf] += siz[uf]; } for(int i = 1; i <= n; ++i) { if(d[i] != 0) { vis[find(d[i])] = true; } } LL ans = 1; for(int i = 1; i <= n; ++i) { if(find(i) == i && !vis[i] && siz[i] > 1) { ans = 2ll * ans % mod; } } cout << ans << "\n"; } signed main() { int T = read(); while(T--) Main(); return 0; }
D. Very Suspicious
找規律題。
考慮兩條不平行的線相交,最多會產生 \(2\) 的貢獻。
因為這個六邊形網路無限大,所以一定會有一個位置,是的當前放的這條線和之前放的所有與它不平行的線相交。
然後記錄一下三種線的數量,每次貪心選擇放當前數量最少的哪一種線就是最優的放法。
然後暴力跑一下 \(n= 10^9\) 的情況,發現只需要三萬多條線。(忘記具體數了)
然後你就可以暴力跑出 \(i\) 條線最多能搞出多少個三角形存下來。
對於每次詢問直接 lower_bound
即可。
#include<bits/stdc++.h>
#define LL long long
//#define int long long
#define orz cout << "tyy YYDS!!!\n"
using namespace std;
const int MAXN = 2e5 + 10;
const int INF = 1e9 + 7;
const int mod = 998244353;
int read() {
int s = 0, f = 0; char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
int biao[MAXN], Cnt = 0;
void Calc(int n) {
int now = 0, ans = 0;
int a = 0, b = 0, c = 0;
while(now < n) {
if(a <= b && a <= c) {
now += 2 * (b + c);
ans ++;
a ++;
} else if(b <= a && b <= c) {
now += 2 * (a + c);
ans ++;
b ++;
} else if(c <= a && c <= b) {
now += 2 * (a + b);
ans ++;
c ++;
}
biao[ans] = now;
}
Cnt = ans;
// cout << ans << "\n";
}
signed main() {
Calc(1500000000);
// cout << Cnt << "\n";
int T = read();
while(T--) {
int n = read();
int x = lower_bound(biao + 1, biao + Cnt + 1, n) - biao;
cout << x << "\n";
}
return 0;
}
E. Hemose on the Tree
發現答案最優一定是 \(2^p\)。
考慮怎麼構造,因為 \(x \oplus (x+2^p) = 2^p\),所以將他們兩兩配對。隨便找一個點放上 \(2^p\) 作為根。
然後可以根據這個點的父親的第 \(p\) 位是否是 \(1\) 來判斷兩個數誰放到邊上誰放到點上。
#include<bits/stdc++.h>
#define LL long long
//#define int long long
#define orz cout << "tyy YYDS!!!\n"
using namespace std;
const int MAXN = 3e5 + 10;
const int INF = 1e9 + 7;
const int mod = 998244353;
int read() {
int s = 0, f = 0; char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
struct edge { int to, id, nxt; }e[MAXN << 1];
int head[MAXN], num_edge = 1;
int p, n, now;
int ans[MAXN], res[MAXN];
void add_edge(int from, int to, int id) { e[++num_edge] = (edge){to, id, head[from]}, head[from] = num_edge; }
void dfs(int u, int fa, int dep) {
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == fa) continue;
ans[v] = ++now;
res[e[i].id] = now + n;
if(!dep) swap(ans[v], res[e[i].id]);
dfs(v, u, dep ^ 1);
}
}
void Main() {
p = read(), n = (1 << p);
num_edge = 1, now = 0;
for(int i = 1; i <= n; ++i) head[i] = 0;
for(int i = 1, u, v; i < n; ++i) {
u = read(), v = read();
add_edge(u, v, i), add_edge(v, u, i);
}
dfs(n, 0, 1);
ans[n] = n;
printf("%d\n", n);
for(int i = 1; i <= n; ++i) printf("%d ", ans[i]); puts("");
for(int i = 1; i < n; ++i) printf("%d ", res[i]); puts("");
}
signed main() {
int T = read();
while(T--) Main();
return 0;
}