- 给出 \(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);
}