省選模擬 19/09/07

WOJ4693 assignment

考場上想了一個 m^3 * n 的 DP
fi,j,k,lf_{i,j,k,l} 表示到 i 最後一個是j,出現了k次,衆數爲l的方案數
用前綴和優化轉移可以做到 m^3 * n
最主要的瓶頸還是在 n,我們用類似離散化的思想,將1–siz 填進去
最後乘上一個 (nsiz)\binom{n}{siz} 就是答案
於是有 m^4 的做法,可以得50分
考慮求出衆數 <= k的答案 p(k)p(k) 然後減去 p(k1)p(k-1)
仍然 DP , fi,jf_{i, j} 表示到第i位,當前數爲 j
fi,j=fi1,j1+fi1,jf_{i,j} = f_{i-1,j-1} + f_{i-1, j}
但是有不合法的,於是有
fi,j=fi1,j1+fi1,jfik1,j1f_{i,j} = f_{i-1,j-1} + f_{i-1, j}-f_{i-k-1,j-1}
ans=k=1mk(p(k)p(k1))/p(m)ans=\sum_{k=1}^m k * (p(k)-p(k-1))/p(m)

#include<bits/stdc++.h>
#define N 255
using namespace std;
const int Mod = 1000000007;
typedef long double ld;
ld f[N][N], c[N], p[N]; int T, m, n;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-')f = -1;}
	while(isdigit(ch)){ cnt = cnt*10 + (ch-'0'), ch = getchar();}
	return cnt * f;
}
int main(){
	T = read();
	while(T--){
		m = read(), n = read(); c[0] = 1;
		for(int i = 1; i <= m; i++) c[i] = c[i-1] * (n - i + 1) / i;
		ld ans = 0;
		memset(p, 0, sizeof(p));
		for(int k = 1; k <= m; k++){
			memset(f, 0, sizeof(f)); f[0][0] = 1;
			for(int i = 1; i <= m; i++){
				for(int j = 1; j <= i; j++){
					f[i][j] = f[i-1][j] + f[i-1][j-1];
					if(i - k - 1 >= 0) f[i][j] -= f[i-k-1][j-1];
				}
			}
			for(int i = 0; i <= m; i++) p[k] += f[m][i] * c[i];
			ans += k * (p[k] - p[k-1]);
		} printf("%.10lf\n", (double)(ans / p[m]));
	} return 0;
}

WOJ4694 fortress
有個比較神奇的構造
因爲每個點打一個是一個匹配的過程,我們考慮對每個點拆成5個點或者更多的點使得這一個連通塊選了一個點過後有3個匹配,選了2,3個過後有2個匹配,選了4個過後有1個匹配,5個過後沒有匹配
這樣一來整個圖的最大匹配就是答案
方法如下:

在這裏插入圖片描述
然後就可以用帶花樹做,現學了一波

#include<bits/stdc++.h>
#define N 805
#define M 500050
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-')f = -1;}
	while(isdigit(ch)){ cnt = cnt*10 + (ch-'0'), ch = getchar();}
	return cnt * f;
}
int n, m, T;
int pos(int a, int b){ return n + (a - 1) * m + b;}
int match[N];
int first[N], nxt[M], to[M], tot;
void add(int x, int y){ 
	nxt[++tot] = first[x], first[x] = tot, to[tot] = y;
	nxt[++tot] = first[y], first[y] = tot, to[tot] = x;
}
int fa[N]; int find(int x){ return x == fa[x] ? x : fa[x] = find(fa[x]);}
int vis[N], pre[N];
int q[N], hd, tl, node;
int exi[N], TIM; 
int lca(int x, int y){
	TIM++; for(;;swap(x, y)){
		if(x){ x = find(x); if(exi[x] == TIM) return x; else exi[x] = TIM, x = pre[match[x]]; }
	}
}
void shrink(int x, int y, int p){
	while(find(x) != p){
		pre[x] = y; y = match[x];
		if(vis[y] == 2) vis[y] = 1, q[++tl] = y;
		if(x == find(x)) fa[x] = p;
		if(y == find(y)) fa[y] = p;
		x = pre[y]; 
	}
}
bool bfs(int s){
	for(int i = 1; i <= node; i++) fa[i] = i; 
	memset(vis, 0, sizeof(vis));
	memset(pre, 0, sizeof(pre));
	hd = tl = 1; q[1] = s; vis[s] = 1;
	while(hd <= tl){
		int x = q[hd++]; 
		for(int i = first[x]; i; i = nxt[i]){
			int t = to[i]; 
			if(find(t) == find(x) && vis[t] == 2) continue;
			if(!vis[t]){
				vis[t] = 2; pre[t] = x;
				if(!match[t]){
					for(int now = t, las; now; now = las){
						las = match[pre[now]]; 
						match[now] = pre[now]; match[pre[now]] = now;
					} return true;
				} vis[match[t]] = 1; q[++tl] = match[t];
			}
			else{
				if(vis[t] == 1){
					int l = lca(x, t);
					shrink(x, t, l); 
					shrink(t, x, l);
				}
			}
		}
	} return false;
}
int id[8][N];
void Yolanda(){
	n = read(), m = read(); node = n;
	for(int d = 1; d <= 7; d++) for(int i = 1; i <= m; i++) id[d][i] = ++node;
	for(int i = 1; i <= n; i++){
		int k = read(); while(k--){
			int x = read();
			for(int d = 1; d <= 5; d++) add(i, id[d][x]);
		}
	}
	for(int i = 1; i <= m; i++){
		for(int d = 1; d <= 5; d++){
			add(id[6][i], id[d][i]); add(id[7][i], id[d][i]);
			if(d <= 4) add(id[d][i], id[d+1][i]);
			else add(id[1][i], id[d][i]);
		}
	} 
	int ans = 0;
	for(int i = 1; i <= node; i++) if(!match[i] && bfs(i)) ans++; 
	cout << ans - n << '\n';
}
void FSY(){ 
	memset(match, 0, sizeof(match));
	memset(exi, 0, sizeof(exi)); TIM = 0;
	memset(first, 0, sizeof(first)); tot = 0;
}
int main(){ T = read(); while(T--) FSY(), Yolanda(); return 0;}

WOJ4695 fibonacci

斐波那契用通項拆開
fn=15((1+52)n(152)n)f_n=\frac{1}{\sqrt 5} *( (\frac{1+\sqrt 5}{2}) ^n- (\frac{1-\sqrt 5}{2}) ^n)
答案可以由 (1+52)n(\frac{1+\sqrt 5}{2})^n 的復部*2 表示
令 x = (1+52)n(\frac{1+\sqrt 5}{2})^n
考慮一個修改u對詢問x的影響
i=kk+depxdepufk=xk+depxdepu+1xkx1\sum_{i=k}^{k+dep_x-dep_u}f_k=\frac{x^{k+dep_x-dep_u+1}-x^k}{x-1}
兩個分開維護,對於前面那個 xk+depxdepu+1=xkdepu+1xdepxx^{k+dep_x-dep_u+1}=x^{k-dep_u+1} * x^{dep_x}
維護前面的即可
然後逆元利用 (a+b5)(a5b)=(a25b2)(a+b * \sqrt 5)(a- \sqrt5 b)=(a^2-5*b^2)

#include<bits/stdc++.h>
#define N 200050
using namespace std;
typedef long long ll;
ll read(){
	ll cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-')f = -1;}
	while(isdigit(ch)){ cnt = cnt*10 + (ch-'0'), ch = getchar();}
	return cnt * f;
}
const int Mod = 1000000007, inv2 = (Mod+1)/2;
ll add(ll a, ll b){ return (a + b) % Mod;}
ll mul(ll a, ll b){ return (a * b) % Mod;}
ll power(ll a, ll b){ ll ans = 1;
	for(;b;b>>=1){ if(b&1) ans = mul(ans, a); a = mul(a, a);}
	return ans;
}
int n, m, fa[N][20], dep[N], st[N], ed[N], sign;
vector<int> v[N];
struct data{
	ll x, y;
	data(ll _x = 0, ll _y = 0){ x = _x, y = _y;}
	data operator + (const data &a){ return data(add(x, a.x), add(y, a.y));}
	data operator - (const data &a){ return data(add(x, Mod-a.x), add(y, Mod-a.y));}
	data operator * (const data &a){ return data(add(mul(x, a.x), mul(5, mul(y, a.y))), add(mul(x, a.y), mul(y, a.x)));}
	data operator + (const ll &a){ return data(add(x, a), y);}
	data operator - (const ll &a){ return data(add(x, Mod-a), y);}
	data operator * (const ll &a){ return data(mul(x, a), mul(y, a));}
};
data base = data(inv2, inv2);
data inv(data a){ return data(a.x, Mod-a.y) * power(add(mul(a.x,a.x), Mod-mul(5, mul(a.y,a.y))), Mod-2);}
data ksm(data a, ll b){ data ans(1, 0);
	for(;b;b>>=1){ if(b&1) ans = ans*a; a = a*a;}
	return ans;
}
void dfs(int u){
	st[u] = ++sign; 
	for(int i = 1; i <= 18; i++) fa[u][i] = fa[fa[u][i-1]][i-1];
	for(int i = 0; i < v[u].size(); i++){ int t = v[u][i];
		fa[t][0] = u; dep[t] = dep[u] + 1; dfs(t); 
	} ed[u] = sign;
}
int lca(int x, int y){
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 18; i >= 0; i--) if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
	if(x == y) return x;
	for(int i = 18; i >= 0; i--) if(fa[x][i] ^ fa[y][i]) x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}
struct Segmentree{
	data tg[N<<2];
	#define mid ((l+r)>>1)
	void build(int x, int l, int r){
		tg[x] = data(0, 0); if(l == r) return; 
		build(x<<1, l, mid); build(x<<1|1, mid+1, r);
	}
	void modify(int x, int l, int r, int L, int R, data k){
		if(L<=l && r<=R){ tg[x] = tg[x] + k; return;}
		if(L<=mid) modify(x<<1, l, mid, L, R, k);
		if(R>mid) modify(x<<1|1, mid+1, r, L, R, k);
	}
	data query(int x, int l, int r, int p){
		if(l == r) return tg[x]; 
		if(p <= mid) return query(x<<1, l, mid, p) + tg[x];
		else return query(x<<1|1, mid+1, r, p) + tg[x];
	}
	#undef mid
}T1, T2;
void upt(int x, ll k){
	data v2 = ksm(base, k), v1 = (v2 * base) * inv(ksm(base, dep[x]));
	T1.modify(1, 1, n, st[x], ed[x], v1);
	T2.modify(1, 1, n, st[x], ed[x], v2);
}
data calc(int x){
	if(!x) return data(0, 0); 
	data ans = T1.query(1, 1, n, st[x]) * ksm(base, dep[x]) - T2.query(1, 1, n, st[x]);
	return ans * inv(base-1);
}
ll Qu(int x, int y){
	int l = lca(x, y); 
	data ans = calc(x) + calc(y) - calc(l) - calc(fa[l][0]);
	return mul(ans.y, 2);
}
int main(){
	n = read(), m = read();
	for(int i = 2; i <= n; i++){
		int x = read(); v[x].push_back(i);
	} dep[1] = 1; dfs(1); T1.build(1, 1, n); T2.build(1, 1, n);
	while(m--){
		char op[3]; scanf("%s", op);
		if(op[0] == 'Q'){ int x = read(), y = read(); cout << Qu(x, y) << '\n';}
		if(op[0] == 'U'){ int x = read(); ll k = read(); upt(x, k);}
	} return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章