T1
可以發現每個果子的貢獻係數是一個組合數,然後由於是異或,只需要求此組合數的奇偶性。組合數長這樣,表示該果子深度(從0開始)。
由lucas定理知只有在二進制或運算時才爲奇數。那麼要讓爲奇數,必須在二進制下跟無相同位置的,否則進位會導致不等於。所以必須是全集異或的子集。
所以可以考慮枚舉子集能過。
我寫的(聽起來高大上,考試時自己推的,還是挺簡單的…)。就是求
就是的或運算的變化。直接類似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
考試只想到DP用NTT優化到,期望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
咕咕咕