0429模擬賽

A

已知一個 n*m 的矩陣,矩陣的每個元素都是非負整數.已知第 i 行的最大值爲 ri ,第 j 列的最大值爲 cj .求矩陣數目。對1e9 + 7 取模。n,m <= 1000

題解

在這裏插入圖片描述
枚舉幾行幾列不滿足條件(即不存在最大值),簡單容斥。
注意前面填了的位置後面不能再填,就把n,m減去對應的行數列數。
時間複雜度O(nm)O(nm)

權值分開算來避免取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。時間複雜度O(nk)O(nk)

#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,那麼子樹和就是這個顏色的答案。就是樹上差分。然後詢問顏色區間就外面套樹狀數組就行了。
時間複雜度O(nlog2n)O(n\log^2n),空間複雜度O(nlog2n)O(n\log^2n)

考試時開三千萬數組寫成三百萬,直接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);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章