A
已知一個 n*m 的矩陣,矩陣的每個元素都是非負整數.已知第 i 行的最大值爲 ri ,第 j 列的最大值爲 cj .求矩陣數目。對1e9 + 7 取模。n,m <= 1000
題解
枚舉幾行幾列不滿足條件(即不存在最大值),簡單容斥。
注意前面填了的位置後面不能再填,就把n,m減去對應的行數列數。
時間複雜度
權值分開算來避免取min想不到(是套路嗎? )。
CODE
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
const int mod = 1e9 + 7;
int r[MAXN], c[MAXN], n, m, ans, b[MAXN<<1];
int C[MAXN][MAXN], pw[MAXN*MAXN], pw2[MAXN*MAXN];
int main () {
C[0][0] = 1;
for(int i = 1; i <= 1000; ++i) {
C[i][0] = 1;
for(int j = 1; j <= i; ++j)
C[i][j] = (C[i-1][j-1] + C[i-1][j]) % mod;
}
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
int T; scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m); int tot = 0;
for(int i = 1; i <= n; ++i) scanf("%d", &r[i]), b[++tot] = r[i];
for(int i = 1; i <= m; ++i) scanf("%d", &c[i]), b[++tot] = c[i];
sort(r + 1, r + n + 1);
sort(c + 1, c + m + 1);
sort(b + 1, b + tot + 1);
tot = unique(b + 1, b + tot + 1) - b - 1;
int ans = 1, cur1 = 1, cur2 = 1, N = n, M = m;
for(int k = 1; k <= tot; ++k) {
int x = 0, y = 0;
while(cur1 <= N && r[cur1] == b[k]) ++x, ++cur1;
while(cur2 <= M && c[cur2] == b[k]) ++y, ++cur2;
int sum = 0, all = x*m + y*n - x*y;
pw[0] = pw2[0] = 1;
for(int i = 1; i <= all; ++i) pw[i] = 1ll*pw[i-1]*(b[k]+1)%mod, pw2[i] = 1ll*pw2[i-1]*b[k]%mod;
for(int i = 0; i <= x; ++i)
for(int j = 0; j <= y; ++j) {
int A = i*m + j*n - i*j;
sum = (sum + (((i+j)&1)?-1ll:1ll) * C[x][i] * C[y][j] % mod * pw[all-A] % mod * pw2[A]) % mod;
}
ans = 1ll * ans * sum % mod;
n -= x, m -= y;
}
printf("%d\n", (ans + mod) % mod);
}
}
B
送你一個 n 個點 m 條邊的 DAG 和參數 k ,定義一條經過 l 條邊的路徑的權值爲 l^k.
對於 i = 1…n,求出所有 1 到 i 的路徑的權值之和,對 998244353 取模.
題解
把次冪展開,就是第二類斯特林和下降冪的乘積,提出一個階乘,可以維護組合數的和就能得到答案。直接拓撲排序+DP。時間複雜度
#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 = 100005;
const int MAXM = 200005;
const int MAXK = 505;
const int mod = 998244353;
int n, m, k, s2[MAXK][MAXK], in[MAXN];
int fir[MAXN], to[MAXM], nxt[MAXM], cnt;
inline void link(int u, int v) {
to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
}
int q[MAXN], s, t, f[MAXN][MAXK], fac[MAXK];
inline void add(int &x, int y) { x += y; x >= mod ? x -= mod : 0; }
inline int pls(int x, int y) { return x + y >= mod ? x+y-mod:x+y; }
int main () {
freopen("B.in", "r", stdin);
freopen("B.out", "w", stdout);
read(n), read(m), read(k);
s2[0][0] = 1; fac[0] = 1;
for(int i = 1; i <= k; ++i) {
s2[i][0] = 0; fac[i] = 1ll*fac[i-1]*i%mod;
for(int j = 1; j <= i; ++j)
s2[i][j] = (s2[i-1][j-1] + 1ll*s2[i-1][j]*j) % mod;
}
for(int i = 0; i <= k; ++i) fac[i] = 1ll*fac[i]*s2[k][i]%mod;
for(int i = 1, u, v; i <= m; ++i)
read(u), read(v), link(u, v), ++in[v];
q[t++] = 1; f[1][0] = 1;
while(s < t) {
int u = q[s++];
for(int i = fir[u], v; i; i = nxt[i]) {
if(!(--in[v=to[i]])) q[t++] = v;
add(f[v][0], f[u][0]);
for(int j = 1; j <= k; ++j)
add(f[v][j], pls(f[u][j], f[u][j-1]));
}
}
for(int i = 1; i <= n; ++i) {
int ans = 0;
for(int j = 0; j <= k; ++j)
ans = (ans + 1ll*fac[j]*f[i][j]) % mod;
printf("%d\n", ans);
}
}
//s2(k, j)*(j!)*C(len,j)
C
送你一棵 n 個點的樹, 樹根爲 1. 一開始每個點上有一個 1…n 的顏色 ci, 不同點顏色可以相同.
現在有 q 次操作, 分爲兩種類型:
• 1 u l r: 詢問子樹 u 中有多少種在 l 到 r 之間的顏色至少出現了一次
• 2 u c: 將 u 的顏色修改爲 c
部分測試點要求強制在線.
n <= 100000
題解
直接相同顏色開set按dfs序排序,然後每個點+1,相鄰lca-1,那麼子樹和就是這個顏色的答案。就是樹上差分。然後詢問顏色區間就外面套樹狀數組就行了。
時間複雜度,空間複雜度
考試時開三千萬數組寫成三百萬,直接100->20。慘。
CODE
#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 = 100005;
const int MAXM = 30000005;
int fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt;
int n, q, T, col[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;
}
int dfn[MAXN], tmr, sz[MAXN], seq[MAXN], son[MAXN], fa[MAXN], dep[MAXN], top[MAXN];
void dfs(int u, int ff) {
dep[u] = dep[fa[u]=ff] + 1;
seq[dfn[u] = ++tmr] = u; sz[u] = 1;
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != ff) {
dfs(v, u), sz[u] += sz[v];
if(sz[v] > sz[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp;
if(son[u]) 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);
}
inline int lca(int u, int v) {
while(top[u] != top[v]) {
if(dep[top[u]] > dep[top[v]]) u = fa[top[u]];
else v = fa[top[v]];
}
return dep[u] < dep[v] ? u : v;
}
int sum[MAXM], lc[MAXM], rc[MAXM], tot, rt[MAXN];
set<int>st[MAXN];
void ins(int &i, int l, int r, int x, int v) {
if(!i) i = ++tot;
sum[i] += v;
if(l == r) return;
int mid = (l + r) >> 1;
if(x <= mid) ins(lc[i], l, mid, x, v);
else ins(rc[i], mid+1, r, x, v);
}
int qsum(int i, int l, int r, int x, int y) {
if(!i) return 0;
if(x <= l && r <= y) return sum[i];
int re = 0, mid = (l + r) >> 1;
if(x <= mid) re += qsum(lc[i], l, mid, x, y);
if(y > mid) re += qsum(rc[i], mid+1, r, x, y);
return re;
}
void upd(int i, int u, int v) {
while(i <= n) {
ins(rt[i], 1, n, dfn[u], v);
i += i&-i;
}
}
int qry(int i, int u) {
int re = 0;
while(i) {
re += qsum(rt[i], 1, n, dfn[u], dfn[u]+sz[u]-1);
i -= i&-i;
}
return re;
}
int main () {
freopen("C.in", "r", stdin);
freopen("C.out", "w", stdout);
read(n), read(q), read(T);
for(int i = 1; i <= n; ++i) read(col[i]);
for(int i = 1, u, v; i < n; ++i) read(u), read(v), link(u, v);
dfs(1, 0), dfs2(1, 1);
for(int i = 1, c, pre; i <= n; ++i) {
st[c=col[seq[i]]].insert(i);
upd(c, seq[i], 1);
set<int>::iterator it = st[c].find(i);
if(it == st[c].begin()) continue;
else {
pre = *(--it);
upd(c, lca(seq[pre], seq[i]), -1);
}
}
int lstans = 0, op, u, l, r, v, c;
while(q--) {
read(op); if(!T) lstans = 0;
if(op == 1) {
read(u), read(l), read(r);
u ^= lstans, l ^= lstans, r ^= lstans;
printf("%d\n", lstans = qry(r, u)-qry(l-1, u));
}
else {
read(u), read(v);
u ^= lstans, v ^= lstans;
int pre = 0, suf = 0;
set<int>::iterator it1, it2;
it1 = it2 = st[c=col[u]].find(dfn[u]); ++it2;
if(it1 == st[c].begin()) pre = 0;
else pre = seq[*(--it1)], upd(c, lca(pre, u), 1);
if(it2 == st[c].end()) suf = 0;
else suf = seq[*it2], upd(c, lca(u, suf), 1);
if(pre && suf) upd(c, lca(pre, suf), -1);
upd(c, u, -1);
st[c].erase(dfn[u]);
c = col[u] = v;
st[c].insert(dfn[u]);
pre = 0, suf = 0;
it1 = it2 = st[c].find(dfn[u]); ++it2;
if(it1 == st[c].begin()) pre = 0;
else pre = seq[*(--it1)], upd(c, lca(pre, u), -1);
if(it2 == st[c].end()) suf = 0;
else suf = seq[*it2], upd(c, lca(u, suf), -1);
if(pre && suf) upd(c, lca(pre, suf), 1);
upd(c, u, 1);
}
}
}