0513 模擬賽 1.FMT 2.分治NTT 3.毒瘤樹剖套線段樹+可刪除堆

T1
在這裏插入圖片描述在這裏插入圖片描述
可以發現每個果子的貢獻係數是一個組合數,然後由於是異或,只需要求此組合數的奇偶性。組合數長這樣(d+t1d)\binom{d+t-1}{d}dd表示該果子深度(從0開始)。

由lucas定理知(nm)\binom{n}{m}只有在二進制或運算nm=nn|m=n時才爲奇數。那麼要讓(d+t1d)\binom{d+t-1}{d}爲奇數,必須t1t-1在二進制下跟dd無相同位置的11,否則進位會導致(d+t1)d(d+t-1)|d不等於(d+t1)(d+t-1)。所以t1t-1必須是全集異或dd的子集。

所以可以考慮枚舉子集3logn3^{\log{n}}能過。

我寫的FMTFMT(聽起來高大上,考試時自己推的,還是挺簡單的…)。就是求fi=ij=i  gjf_i=\oplus_{i|j=i}\ \ g_j

就是FWTFWT的或運算的變化。直接類似FFT一樣分治求,每次考慮一位就行了。見代碼。

但標算是分塊在這裏插入圖片描述

#include <bits/stdc++.h>
using namespace std;
inline void read(int &x) {
	char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
	for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0'); x*=flg;
}
const int MAXN = 265000;
int n, m, mxd, a[MAXN], fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt, dep[MAXN];
inline void link(int u, int v) {
	to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
	to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
void dfs(int u, int ff) {
	mxd = max(mxd, dep[u] = dep[ff] + 1);
	for(int i = fir[u]; i; i = nxt[i])
		if(to[i] != ff) dfs(to[i], u);
}
int w[MAXN];
inline bool chk(int n, int m) { return (n|m) == n; }
void FWT(int arr[], int len) {
	for(int i = 2; i <= len; i<<=1)
		for(int j = 0; j < len; j += i)
			for(int k = j; k < j+i/2; ++k)
				w[k+i/2] ^= w[k];
}
int main () {
	read(n), read(m);
	for(int i = 1, x, y; i < n; ++i) read(x), read(y), link(x, y);
	dep[0] = -1; dfs(1, 0);
	for(int i = 1; i <= n; ++i) read(a[i]), w[dep[i]] ^= a[i];
	int len = 1, B = 0; while(len <= mxd) len<<=1, ++B;
	FWT(w, len);
	int k;
	while(m--) {
		read(k);
		if(!k) printf("%d\n", a[1]);
		else {
			int sub = 0; --k;
			for(int i = 0; i < B; ++i)
				if(!(k>>i&1)) sub |= 1<<i;
			printf("%d\n", w[sub]);
		}
	}
}

T2
在這裏插入圖片描述在這裏插入圖片描述
考試只想到n3n^3DP用NTT優化到n2lognn^2\log n,期望50分但是老年評測機,大家寫50的都只有30。。

正解就是進一步推式子(大力推或者用生成函數推)。見下題解。
在這裏插入圖片描述在這裏插入圖片描述
學了一下高效預處理原根的冪。

#include <bits/stdc++.h>
using namespace std;
inline void read(int &x) {
	char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
	for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0'); x*=flg;
}
const int mod = 998244353, G = 3;
const int MAXN = 131100;
int n, fac[MAXN], inv[MAXN], rev[MAXN], Wl, Wl2, gen[MAXN];
inline int qpow(int a, int b) {
	int re = 1;
	for(; b; b>>=1, a=1ll*a*a%mod)if(b&1)re=1ll*re*a%mod;
	return re;
}
inline int add(int x, int y) { return x+y >= mod ? x+y-mod : x+y; }
void NTT(int arr[], int len, int flg) {
	for(int i = 0; i < len; ++i) if(i < rev[i]) swap(arr[i], arr[rev[i]]);
	for(int i = 2, v, B = Wl; i <= len; i<<=1, B>>=1)
		for(int j = 0; j < len; j += i)
			for(int k = j, x = 0; k < j+i/2; ++k, x += B)
				arr[k+i/2] = add(arr[k], mod-(v = 1ll * arr[k+i/2] * gen[flg==1?x:Wl2-x] % mod)), arr[k] = add(arr[k], v);
	if(flg == -1) {
		int iv = qpow(len, mod-2);
		for(int i = 0; i < len; ++i) arr[i] = 1ll*arr[i]*iv%mod;
	}
}
int f[MAXN], g[MAXN], w[MAXN];
vector<int> solve(int l, int r) {
	if(l == r) {
		vector<int> re;
		re.push_back(1), re.push_back(w[l]);
		return re;
	}
	int mid = (l + r) >> 1;
	vector<int>L = solve(l, mid);
	vector<int>R = solve(mid+1, r);
	int len = 1; while(len <= r-l+1) len<<=1;
	for(int i = 1; i < len; ++i) rev[i] = (rev[i>>1]>>1)|((i&1)*(len>>1));
	for(int i = 0; i <= mid-l+1; ++i) f[i] = L[i];
	for(int i = mid-l+2; i < len; ++i) f[i] = 0;
	for(int i = 0; i <= r-mid; ++i) g[i] = R[i];
	for(int i = r-mid+1; i < len; ++i) g[i] = 0;
	NTT(f, len, 1), NTT(g, len, 1);
	for(int i = 0; i < len; ++i) f[i] = 1ll*f[i]*g[i]%mod;
	NTT(f, len, -1);
	vector<int>re;
	for(int i = 0; i <= r-l+1; ++i) re.push_back(f[i]);
	return re;
}
void init(int N) {
	for(Wl = 1; Wl<<1 <= N; Wl<<=1); Wl2 = Wl<<1;
	gen[0] = 1, gen[1] = qpow(G, (mod-1)/Wl2);
	for(int i = 2; i <= Wl2; ++i) gen[i] = 1ll * gen[i-1] * gen[1] % mod;
	fac[0] = inv[0] = fac[1] = inv[1] = 1;
	for(int i = 2; i <= N; ++i) fac[i] = 1ll*fac[i-1]*i%mod, inv[i] = 1ll*(mod-mod/i)*inv[mod%i]%mod;
	for(int i = 2; i <= N; ++i) inv[i] = 1ll*inv[i]*inv[i-1]%mod;
}
int main () {
	read(n);
	if(n == 1) { puts("0"); return 0; }
	init(n);
	int sum = 0, cf = fac[n-2];
	for(int i = 1; i <= n; ++i) read(w[i]), sum = (sum + w[i]) % mod, cf = 1ll * cf * w[i] % mod;
	vector<int>F = solve(1, n);
	int ans = 0;
	for(int k = 0; k <= n-2; ++k)
		ans = (ans + 1ll * F[k] * qpow(sum, n-k-2) % mod * inv[n-k-2]) % mod;
	ans = 1ll * ans * cf % mod;
	printf("%d", (ans + mod) % mod);
}

T3
咕咕咕在這裏插入圖片描述
在這裏插入圖片描述
挺嘔心得一道題

#include <bits/stdc++.h>
using namespace std;
inline void read(int &x) {
	char ch; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
	for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0'); x*=flg;
}
typedef long long LL;
typedef pair<LL,LL> pLL;
const int MAXN = 265000;
struct Heap {
	priority_queue<LL>I, O;
	inline void ins(LL x) { I.push(x); }
	inline void del(LL x) { O.push(x); }
	inline LL top() {
		while(!O.empty() && I.top() == O.top()) I.pop(), O.pop();
		if(!I.empty()) return I.top();
		return 0;
	}
	pLL ask() {
		LL x = top(); del(x);
		LL y = top(); ins(x);
		return pLL(x, y);
	}
}Q[MAXN], all;
int n, m, fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt;
inline void link(int u, int v) {
	to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
	to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
int sz[MAXN], dep[MAXN], fa[MAXN], son[MAXN], top[MAXN], l[MAXN], r[MAXN], tmr, ln[MAXN];
void dfs1(int u, int ff) {
	dep[u] = dep[fa[u]=ff] + (sz[u]=1);
	for(int i = fir[u], v; i; i = nxt[i])
		if((v=to[i]) != ff) {
			dfs1(v, u); sz[u] += sz[v];
			if(sz[v] > sz[son[u]]) son[u] = v;
		}
}
int rt[MAXN], lc[MAXN<<2], rc[MAXN<<2], tot;
LL lm[MAXN<<2], rm[MAXN<<2], sum[MAXN<<2], ans[MAXN<<2], lz[MAXN<<2], vl[MAXN<<2];
void build(int &i, int l, int r) {
	i = ++tot;
	if(l == r) return;
	int mid = (l + r) >> 1;
	build(lc[i], l, mid);
	build(rc[i], mid+1, r);
}
void dfs2(int u, int tp) {
	top[u] = tp; l[u] = ++tmr;
	if(!son[u]) {
		ln[tp] = tmr;
		build(rt[tp], l[tp], l[u]);
		all.ins(0);
	}
	else dfs2(son[u], tp);
	for(int i = fir[u], v; i; i = nxt[i])
		if((v=to[i]) != fa[u] && v != son[u])
			dfs2(v, v), Q[u].ins(0);
	r[u] = tmr;
}
inline void upd(int i) {
	sum[i] = sum[lc[i]] + sum[rc[i]] + vl[i] + lz[i];
	lm[i] = max(lm[lc[i]], sum[lc[i]] + vl[i] + lm[rc[i]]) + lz[i];
	rm[i] = max(rm[rc[i]], sum[rc[i]] + vl[i] + rm[lc[i]]) + lz[i];
	ans[i] = max(max(ans[lc[i]], ans[rc[i]]), rm[lc[i]] + vl[i] + lm[rc[i]]) + lz[i];
}
void update(int i, int l, int r, int x, int y, int v) {
	if(x == l && r == y) {
		lm[i] += v; rm[i] += v;
		lz[i] += v; sum[i] += v; ans[i] += v;
		return;
	}
	int mid = (l + r) >> 1;
	if(y <= mid) update(lc[i], l, mid, x, y, v);
	else if(x > mid) update(rc[i], mid+1, r, x, y, v);
	else update(lc[i], l, mid, x, mid, v), update(rc[i], mid+1, r, mid+1, y, v), vl[i] -= v;
	upd(i);
}
LL lav[MAXN], val[MAXN];
void updans(int i, int l, int r, int x, pLL v) {
	if(l == r) {
		ans[i] = lz[i] + v.first + v.second;
		lm[i] = rm[i] = lz[i] + v.first;
		return;
	}
	int mid = (l + r) >> 1;
	if(x <= mid) updans(lc[i], l, mid, x, v);
	else updans(rc[i], mid+1, r, x, v);
	upd(i);
}
bool UPDATE(int x) {
	int pr = fa[x];
	if(!pr || lav[x] == lm[rt[x]] + val[x]) return 0;
	Q[pr].del(lav[x]);
	lav[x] = lm[rt[x]] + val[x];
	Q[pr].ins(lav[x]);
	updans(rt[top[pr]], l[top[pr]], ln[top[pr]], l[pr], Q[pr].ask());
	return 1;
}
LL f[MAXN];
void addans(int x) {
	if(f[x] == ans[rt[x]]) return;
	all.del(f[x]);
	f[x] = ans[rt[x]];
	all.ins(f[x]);
}
void modify(int x, int y, int v) {
	while(top[x] != top[y]) {
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		update(rt[top[x]], l[top[x]], ln[top[x]], l[top[x]], l[x], v);
		val[x=top[x]] -= v;
		UPDATE(x), addans(x);
		x = fa[x];
	}
	if(dep[x] > dep[y]) swap(x, y);
	update(rt[top[x]], l[top[x]], ln[top[x]], l[x], l[y], v);
	for(addans(x=top[x]); x && UPDATE(x); addans(x=top[fa[x]]));
}
int X[MAXN], Y[MAXN], W[MAXN];
int main () {
	freopen("kaguya1.in", "r", stdin);
	freopen("ay.out", "w", stdout);
	read(n), read(m);
	for(int i = 1, u, v; i < n; ++i)
		read(u), read(v), link(u, v);
	dfs1(1, 0), dfs2(1, 1);
	char s[2];
	for(int i = 1, x; i <= m; ++i) {
		scanf("%s", s);
		if(s[0] == '+') {
			read(X[i]), read(Y[i]), read(W[i]);
			modify(X[i], Y[i], W[i]);
		}
		else {
			read(x);
			modify(X[x], Y[x], -W[x]);
		}
		printf("%lld\n", all.top());
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章