1. 程式人生 > 其它 >如何設定SVN提交時必須輸入註釋(不少於2個字元) 如何設定SVN提交時必須輸入註釋

如何設定SVN提交時必須輸入註釋(不少於2個字元) 如何設定SVN提交時必須輸入註釋

Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round)

擁有良好的比賽體驗(

A,B 比較 naive。

C - Alice and the Cake

初始有一塊蛋糕,每次可以選擇一塊蛋糕,設其大小為 \(w\),要求 \(w\geq 2\)

並將其劈為 \(\lfloor \frac{w}{2}\rfloor\)\(\lceil \frac{w}{2}\rceil\) 兩塊。

現給出最終蛋糕序列,求這是否是能被產生的蛋糕序列。

賽時想了一會自底向上的合併,然而並不知道合併優先順序是啥。

然後發現蛋糕大小之和是不會變的,相當於起點也知道,可以直接模擬這個過程。

然後就上了一個佇列,每次能消就直接消,交了一發 MLE。

發現當前分到的大小 \(<\) 初始序列的最小值顯然是不和法的,可以直接 break,又交了一發 MLE。

然後恍然大悟,改成小根堆。

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;
 
int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}
 
map<int, int> c;
 
int main() {
	int T = read();
	while(T --) {
		int n = read(); LL s = 0;
		c.clear();
		int Mn = 2e9;
		while(n --) {int x = read(); c[x] ++, s += x, Mn = min(Mn, x);}
		priority_queue<LL, vector<LL>, greater<LL> > q;
		q.push(s);
		while(! q.empty()) {
			LL x = q.top(); q.pop();
			if(c.find(x) != c.end()) {if(! -- c[x]) c.erase(x);}
			else {
				if((x >> 1) < (c.begin() -> first)) break;
				q.push(x >> 1);
				q.push((x >> 1) + (x & 1));
			}
		}
		if(c.begin() != c.end()) puts("NO"); else puts("YES");
	}
	return 0;
}

D - Potion Brewing Class

構造長度為 \(n\) 的正整數序列。給定 \(n-1\) 對比例關係,形如 \((i,j,x,y)\) 表示 \(a_i/a_j=x/y\)

保證關係能唯一確定所有數的比值關係(樹連通),求序列和的最小值,對 \(998244353\) 取模。

確定根,每個點與根的關係都可以得到,和最小根顯然取所有分式的 \(\text{lcm}\),相當於求帶 \(\bmod\)\(\text{lcm}\)

考慮每個質因子拆開,直接算每個質因子在分母中出現過的最大次數。

實際上維護一個全域性桶就好了,進入子樹時加上,離開子樹時減去,時刻取 \(\max\)

然後賽時頭腦一熱寫了個可持久化線段樹,調了半天,發現如果 \(x=y=1\) 需要令 \(\text{rt}(i)=\text{rt}(fa_i)\)

反正過了就還好(

實際上極限資料空間可能可以卡爆(

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;
 
const int N = 2e5 + 10;
const int P = 998244353;
 
int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}
 
int Pow(int a, int b) {
	int s = 1;
	for(; b; b >>= 1, a = 1LL * a * a % P)
		if(b & 1) s = 1LL * s * a % P;
	return s;
}
 
int n, t, p[N], c[N], id[N];
bool v[N];
 
int cnt, head[N];
struct Edge {int nxt, v, x, y;} e[N << 1];
 
void add(int u, int v, int x, int y) {e[++ cnt] = (Edge) {head[u], v, x, y}; head[u] = cnt;}
 
int rt[N], tot;
struct Tree {int l, r, dat, laz;} tr[N * 40]; // 這裡應該要開 log^2 的,但是開不下(
 
int New() {
	tr[++ tot] = (Tree) {0, 0, 0, 0};
	return tot;
}
 
int Bui(int l, int r) {
	int p = New(); if(l == r) return p;
	int mid = (l + r) >> 1;
	tr[p].l = Bui(l, mid);
	tr[p].r = Bui(mid + 1, r);
	return p;
}
 
int Ins(int las, int p, int l, int r, int k, int v, bool o, int h) {
	if(! p || tr[p].laz != h) p = New(), tr[p] = tr[las], tr[p].laz = h;
	if(l == r) {
		tr[p].dat += v;
		if(o) c[k] = max(c[k], tr[p].dat);
		return p;
	}
	int mid = (l + r) >> 1;
	if(k <= mid)
		tr[p].l = Ins(tr[las].l, tr[p].l, l, mid, k, v, o, h);
	else
		tr[p].r = Ins(tr[las].r, tr[p].r, mid + 1, r, k, v, o, h);
	return p; 
}
 
vector<int> arc;
 
void dfs1(int u, int fa, int x, int y) {
	// fa * y / x = u
	for(int i = 1; i <= t && 1LL * p[i] * p[i] <= x; i ++) if(x % p[i] == 0) {
		int num = 0;
		while(x % p[i] == 0) num ++, x /= p[i];
		rt[u] = Ins(rt[fa], rt[u], 1, t, i, num, 0, u), arc.push_back(i);
	}
	if(x > 1)
		rt[u] = Ins(rt[fa], rt[u], 1, t, id[x], 1, 0, u), arc.push_back(id[x]);
 
	for(int i = 1; i <= t && 1LL * p[i] * p[i] <= y; i ++) if(y % p[i] == 0) {
		int num = 0;
		while(y % p[i] == 0) num ++, y /= p[i];
		rt[u] = Ins(rt[fa], rt[u], 1, t, i, - num, 0, u);
	}
	if(y > 1)
		rt[u] = Ins(rt[fa], rt[u], 1, t, id[y], - 1, 0, u);
 
	if(! rt[u]) rt[u] = rt[fa];
	for(int v : arc) Ins(rt[fa], rt[u], 1, t, v, 0, 1, u);
	arc.clear();
 
	Ede(i, u) if(e[i].v != fa) dfs1(e[i].v, u, e[i].x, e[i].y);
}
 
int ans;
 
void dfs2(int u, int num, int fa) {
	ans = (ans + num) % P;
	Ede(i, u) if(e[i].v != fa) {
		int nxt = 1LL * num * e[i].y % P * Pow(e[i].x, P - 2) % P;
		dfs2(e[i].v, nxt, u);
	}
}
 
void clear() {
	ans = tot = cnt = t = 0;
	rep(i, 1, n) c[i] = rt[i] = head[i] = 0, v[i] = false;
}
 
void Work() {
	n = read();
	clear();
	rep(i, 2, n) {
		if(! v[i]) id[p[++ t] = i] = t;
		for(int j = 1; j <= t && p[j] * i <= n; j ++) {
			v[p[j] * i] = true;
			if(i % p[j] == 0) break; 
		}
	}
	rep(i, 2, n) {
		int u = read(), v = read();
		int x = read(), y = read();
		add(u, v, x, y);
		add(v, u, y, x);
	}
	rt[0] = Bui(1, t);
	dfs1(1, 0, 0, 0);
	int one = 1;
	rep(i, 1, t) one = 1LL * one * Pow(p[i], c[i]) % P;
	dfs2(1, one, 0);
	printf("%d\n", ans);
}
 
int main() {int T = read(); while(T --) Work(); return 0;}

E - Arithmetic Operations

給定序列,值域和長度都 \(\leq 10^5\),可以對單點進行任意次修改。

求將序列變為等差數列的最小修改次數。空間 1GB。

沒想到竟是根號分治題。

對公差 \(d\) 進行討論:

  • \(d\leq \sqrt V\),直接列舉每個 \(d\),開一個桶統計 \(a_i-i\times d\) 相同的最大值即可。
  • \(d>\sqrt V\),列舉不改變的點,以它為中心,只有 \(\pm \sqrt V\) 個位置可能也保持不變,統計即可。

空間很大,直接開 \(7\times 10^7\) 的陣列當桶,unordered_map 反而會被卡常。

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;
 
const int N = 1e5 + 10, M = 310;
const int R = 7e7, D = R / 2;
int n, a[N], cnt[R];
 
int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}
 
int main() {
	n = read();
	rep(i, 1, n) a[i] = read();
	int ans = 0;
	rep(d, - M, M) {
		rep(i, 1, n) if(a[i] - i * d + D >= 0 && a[i] - i * d + D < R)
				ans = max(ans, ++ cnt[a[i] - i * d + D]);
		rep(i, 1, n) if(a[i] - i * d + D >= 0 && a[i] - i * d + D < R)
				cnt[a[i] - i * d + D] --;
	}
	rep(i, 1, n) {
		rep(j, max(1, i - M), min(i + M, n))
			if(i != j && (a[i] - a[j]) % (i - j) == 0)
				ans = max(ans, (++ cnt[(a[i] - a[j]) / (i - j) + D]) + 1);
		rep(j, max(1, i - M), min(i + M, n))
			if(i != j && (a[i] - a[j]) % (i - j) == 0)
				cnt[(a[i] - a[j]) / (i - j) + D] --;
	}
	printf("%d\n", n - ans);
	return 0; 
}

F - Minimal String Xoration

給定字串 \(s\),長度為 \(2^n\)。定義 \(T_i(i\in [0,2^n-1])\),其中 \(\forall j\in[0,2^n-1],t_{j}=s_{j\oplus i}\)

求字典序最小的 \(T\)

很有趣的題目。

實際上,可以考慮對所有 \(T_i\) 排序,過程和字尾陣列的構造過程十分類似。

\(rk(i,j)\) 表示 \(T_i\),按照前 \(2^j\) 的字典序排序的排名。

顯然 \(rk(i,j)\) 可以由 \(rk(i,j-1),rk(i\oplus2^{j-1},j-1)\) 兩者的排名得到,優先順序按順序。

因為 \(i\) 的前 \(j\) 位恰由 \(i\) 的前 \(j-1\) 位與 \(i\oplus 2^{j-1}\) 的前 \(j-1\) 位構成。

直接基數排序 + 倍增就可以做到 \(O(n2^n)\) 了。

#include<bits/stdc++.h>
typedef long long LL;
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

const int N = (1 << 18) + 10, M = 20;
int n, m, sa[N], rk[N], SA[N], RK[N], bac[N];
char str[N];

int main() {
	scanf("%d %s", &m, str);
	n = (1 << m) - 1;
	rep(i, 0, n) bac[str[i] - 'a'] ++;
	rep(i, 1, 25) bac[i] += bac[i - 1];
	rep(i, 0, n) sa[-- bac[str[i] - 'a']] = i;
	rk[sa[0]] = 1;
	rep(i, 1, n) rk[sa[i]] = rk[sa[i - 1]] + (str[sa[i]] != str[sa[i - 1]]);
	
	rep(o, 1, m) {
		rep(i, 1, n + 1) bac[i] = 0;
		rep(i, 0, n) ++ bac[rk[i]];
		rep(i, 1, n + 1) bac[i] += bac[i - 1];
		per(i, n, 0) SA[-- bac[rk[sa[i] ^ (1 << (o - 1))]]] = (sa[i] ^ (1 << (o - 1)));
		#define comp(x, y) (rk[x] != rk[y] || rk[x ^ (1 << (o - 1))] != rk[y ^ (1 << (o - 1))])
		RK[SA[0]] = 1;
		rep(i, 1, n) RK[SA[i]] = RK[SA[i - 1]] + comp(SA[i], SA[i - 1]);
		rep(i, 0, n) sa[i] = SA[i], rk[i] = RK[i];
		if(rk[sa[n]] == n) break;
	}
	int ans = sa[0];
	rep(i, 0, n) putchar(str[i ^ ans]); puts("");
	return 0;
}