NOI Oline 2題解

A

假設 p1 < p2
對於lcm(p1, p2)肯定是選擇塗成 p2的顏色,因爲左右最近的都是p1顏色的
考慮最差的情況, 兩個p2顏色的格子塞了最多的p1顏色。
兩個p2顏色中間有p2-1個格子
最差的情況就是這p2-1個格子中第一個被染了p1顏色,然後每隔p1個染p1色
也就是

p211p1+1\frac{p_2-1 -1}{p1} + 1

和k比較一下就好了
注意k=1的情況

code:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t, p1, p2, k;
signed main() {
	scanf("%lld", &t);
	while(t --) {
		scanf("%lld%lld%lld", &p1, &p2, &k);
		if(p1 > p2) swap(p1, p2);
		int d = __gcd(p1, p2);
		p1 /= d, p2 /= d;
		if(k == 1 || (p2 > 2 && (p2 - 2) / p1 + 1 >= k)) printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}

B

沒啥好說的呀
根據套路
g(r)=l=1rf(l,r)g(r) = \sum\limits_{l=1}^r f(l,r)
ANS=r=1ng(r)ANS = \sum\limits_{r=1}^ng(r)

像這種求集合大小的只需要考慮每個數對那些集合有貢獻就行了
記個 pre[i]表示上一個和 i 相同的位置
動態維護f(l, r)
考慮從g( r - 1)轉移到 g( r )
發現r只對l在[pre[r] + 1, r]有貢獻
即 對於l在這個區間內的 f ( l, r) = f(l, r - 1) + 1
平方一下
然後和原始相減就可以發現只用求 一段區間f(l, r - 1)

即需要一個數據結構維護區間加,區間求和
線段樹好像會被卡常,用樹狀數組就好了

code:

#include<bits/stdc++.h>
#define mod 1000000007
#define N 1000005
#define int long long
#define lowbit(x) (x & -x)
using namespace std;
inline void MOD(int &x) {
	if(x < 0) x += mod;
	if(x >= mod) x -= mod;
}
int tree1[N + 5], tree2[N + 5];
void update1(int x, int y) {
	for(; x < N; x += lowbit(x)) tree1[x] += y, MOD(tree1[x]);
}
int query1(int x) {
	int ret = 0;
	for(; x; x -= lowbit(x)) ret += tree1[x], MOD(ret);
	return ret;
} 
void update2(int x, int y) {
	for(; x < N; x += lowbit(x)) tree2[x] += y, MOD(tree2[x]);
}
int query2(int x) {
	int ret = 0;
	for(; x; x -= lowbit(x)) ret += tree2[x], MOD(ret);
	return ret;
}
void add(int l, int r, int o) {
	update1(l, o % mod), update1(r + 1, - o % mod);
	update2(l, o * l % mod), update2(r + 1, - o * (r + 1) % mod);
}
int query(int x) {
	return ((x + 1) * query1(x) % mod - query2(x) + mod) % mod;
}
int n, a[N], b[N], mp[N], pre[N];
signed main() {
	scanf("%lld", &n);
	for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]), b[i] = a[i];
	sort(b + 1, b + 1 + n);
	for(int i = 1; i <= n; i ++) {
		int pos = lower_bound(b + 1, b + 1 + n, a[i]) - b;
		pre[i] = mp[pos];
		mp[pos] = i;
	}
	//for(int i = 1; i <= n; i ++) printf("%d ", pre[i]); printf("\n");
	int last = 0, ans = 0;
	for(int r = 1; r <= n; r ++) {
		last += 2 * (query(r) - query(pre[r]) + mod) % mod + r - pre[r], last %= mod;
		ans += last, ans %= mod;
		add(pre[r] + 1, r, 1);
	}
	printf("%lld", ans);
	return 0;
}

C

首先要知道二項式反演
在這裏插入圖片描述

根據之前做多項式的套路,可以設 g(i)爲恰好i次非平局, f(i)爲欽定i次非平局
然後f(i)可以直接樹形DP出來,再根據二項式定理就可以算出 g(i)了
答案就是 g(i)\sum g(i)

code:

#include<bits/stdc++.h>
#define int long long
#define mod 998244353
#define N 10005
using namespace std;
int fac[N], ifac[N];
int qpow(int x, int y) {
	int ret = 1;
	for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
	return ret;
}
int C(int x, int y) {
	return fac[x] * ifac[x - y] % mod * ifac[y] % mod;
}
struct edge {
	int v, nxt;
} e[N << 1];
int p[N], eid;
void init() {
	memset(p, -1, sizeof p);
	eid = 0;
}
void insert(int u, int v) {
	e[eid].v = v;
	e[eid].nxt = p[u];
	p[u] = eid ++;
}
int size[N], sza[N], dp[N][N], a[N], ls[N], n, f[N];
void dfs(int u, int fa) {
	size[u] = 1, sza[u] = a[u];
	dp[u][0] = 1;
	for(int i = p[u]; i + 1; i = e[i].nxt) {
		int v = e[i].v;
		if(v == fa) continue;
		dfs(v, u);
		for(int j = 0; j <= size[u] + size[v]; j ++) ls[j] = 0;
		for(int j = 0; j <= size[u] / 2; j ++) 
			for(int k = 0; k <= size[v] / 2; k ++) 
				ls[j + k] += dp[u][j] * dp[v][k] % mod, ls[j + k] %= mod;
		for(int j = 0; j <= size[u] + size[v]; j ++) dp[u][j] = ls[j];
		size[u] += size[v], sza[u] += sza[v];
	}
	for(int i = min(sza[u], size[u] - sza[u]); i >= 1; i --)
		dp[u][i] += dp[u][i - 1] * (a[u]? (size[u] - sza[u] - (i - 1)) : (sza[u] - (i - 1))) % mod, dp[u][i] %= mod;
}
signed main() {
	init();
	scanf("%lld", &n);
	ifac[0] = fac[0] = 1;
	for(int i = 1; i <= n; i ++) fac[i] = fac[i - 1] * i % mod;
	ifac[n] = qpow(fac[n], mod - 2); for(int i = n - 1; i >= 1; i --) ifac[i] = ifac[i + 1] * (i + 1) % mod;
	for(int i = 1; i <= n; i ++) {
		char ch;
		scanf(" %c", &ch);
		if(ch == '0') a[i] = 0;
		else a[i] = 1;
	}
	for(int i = 1; i < n; i ++) {
		int u, v;
		scanf("%lld%lld", &u, &v);
		insert(u, v);
		insert(v, u);
	}
	dfs(1, 1);
	for(int i = 0; i <= n / 2; i ++) f[i] = dp[1][i] * fac[n / 2 - i] % mod;
	for(int i = 0; i <= n / 2; i ++) {
		int ret = 0;
		for(int j = i; j <= n / 2; j ++) 
			ret += C(j, i) * ((j - i & 1) ? mod - 1 : 1) % mod * f[j] % mod + mod, ret %= mod;
		printf("%lld\n", ret);
	}
	return 0;
}

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