1. 程式人生 > 實用技巧 >CF 1425B Blue and Red of Our Faculty!

CF 1425B Blue and Red of Our Faculty!

  • 給出 \(m\) 個環,它們兩兩之間有且僅有一個交點 \(1\),求出有多少種選擇出 兩條起點為 \(1\) 長度相同的路徑分別記為 \(Red,Blue\),且邊沒有重複,並且不能夠再拓展 的方案數,兩種方案不同當且僅當至少對應的 \(Red,Blue\) 中至少有一個選取邊的集合不同,保證環長度的總和小於 \(4000\)

顯然最後結束時兩人相距不超過 \(1\),否則它們均可以再走一步。

每人走的路徑集合必定有若干個完整的環,可以再接一段殘缺的環。

那麼考慮按照最終的位置分別統計。

\(1\) 處相遇,那麼就是將所有環劃分為兩個不同集合,求每個集合的環長度之和相等。

均走進了同一個環,且相距為 \(0/1\)

,那麼就是選出一個環分配給兩人正整數長度,再將剩下的由兩人分,可以不選某個環,總和相同的方案數。

只有 \(1\) 人走進環並且距離,另外一人在 \(1\) 處,相距為 \(1\),那麼就是選出一個環的長度減 \(1\),剩下的由兩人分完,總和相同的方案數。

都可以用類似於揹包的方法搞。

#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define fi first
#define se second
using namespace std;

typedef long long LL;
typedef pair <int, int> P;
const int inf = 0x3f3f3f3f, N = 2005, mod = 1e9 + 7;
template <typename T>
void rd_(T &x) {
	x = 0; int f = 1;
	char ch = getchar();
	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x*10 + ch - '0';x *= f;
}

vector <int> h[N];
int n, m, s[N], tot, f[2][N<<2][2], cur, g[2][N<<2], ans;
bool vis[N];

void dfs_(int u) {
	vis[u] = 1, s[tot]++;
	for (int v, i = 0; i < (int) h[u].size(); i++) {
		v = h[u][i];
		if (vis[v]) continue;
		dfs_(v);
	}
}

int main() {
	rd_(n), rd_(m);
	for (int u, v, i = 1; i <= m; i++) {
		rd_(u), rd_(v);
		h[u].push_back(v), h[v].push_back(u);
	}
	vis[1] = 1;
	rep (i, 0, (int) h[1].size() - 1) {
		int u = h[1][i];
		if (!vis[u]) {
			s[++tot] = 1;
			dfs_(u);
		}
	}
	f[0][m][0] = 1;
	rep (i, 1, tot) {
		cur ^= 1;
		rep (j, 0, 2*m) {
			f[cur][j][0] = f[cur^1][j][0];
			f[cur][j][1] = f[cur^1][j][1];
			if (j >= s[i]) {
				f[cur][j][0] = (f[cur][j][0] + f[cur^1][j - s[i]][0])%mod;
				f[cur][j][1] = (f[cur][j][1] + f[cur^1][j - s[i]][1])%mod;
			}
			if (j + s[i] <= 2*m) {
				f[cur][j][0] = (f[cur][j][0] + f[cur^1][j + s[i]][0])%mod;
				f[cur][j][1] = (f[cur][j][1] + f[cur^1][j + s[i]][1])%mod;
			}
			rep (k, 1, s[i] - 1) {
				int d = 2*k - s[i];
				if (j >= d) f[cur][j][1] = (f[cur][j][1] + f[cur^1][j - d][0]*2ll)%mod;
			}
			rep (k, 1, s[i] - 2) {
				int d = 2*k - s[i] + 1;
				if (j >= d) f[cur][j][1] = (f[cur][j][1] + f[cur^1][j - d][0]*2ll)%mod;
			}
		}
	}
	ans = f[cur][m][1];
	g[cur = 0][m] = 1;
	rep (i, 1, tot) {
		cur ^= 1;
		rep (j, 0, 2*m) {
			g[cur][j] = 0;
			if (j >= s[i]) g[cur][j] = (g[cur][j] + g[cur^1][j - s[i]])%mod;
			if (j + s[i] <= 2*m) g[cur][j] = (g[cur][j] + g[cur^1][j + s[i]])%mod;
		}
	}
	ans = (ans + g[cur][m])%mod;
	memset(f, 0, sizeof(f));
	f[cur = 0][m][0] = 1;
	rep (i, 1, tot) {
		cur ^= 1;
		rep (j, 0, 2*m) {
			f[cur][j][0] = 0;
			f[cur][j][1] = 0;
			if (j >= s[i]) {
				f[cur][j][0] = (f[cur][j][0] + f[cur^1][j - s[i]][0])%mod;
				f[cur][j][1] = (f[cur][j][1] + f[cur^1][j - s[i]][1])%mod;
			}
			if (j + s[i] <= 2*m) {
				f[cur][j][0] = (f[cur][j][0] + f[cur^1][j + s[i]][0])%mod;
				f[cur][j][1] = (f[cur][j][1] + f[cur^1][j + s[i]][1])%mod;
			}
			if (j + s[i] - 1 <= 2*m)
				f[cur][j][1] = (f[cur][j][1] + f[cur^1][j + s[i] - 1][0]*2ll)%mod;
			if (j - (s[i] - 1) >= 0)
				f[cur][j][1] = (f[cur][j][1] + f[cur^1][j - s[i] + 1][0]*2ll)%mod;
		}
	}
	ans = (ans + f[cur][m][1])%mod;
	printf("%d\n", ans);
}