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
挺嘔心得一道題
#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());
}
}