0513 模擬賽 1.FMT 2.分治NTT 3.毒瘤樹剖套線段樹套multiset

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
咕咕咕在這裏插入圖片描述
咕咕咕

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章