BZOJ2169 连边(动态规划)
令f[i][j]表示连i条边时奇点个数为j的方案数,转移时讨论两奇点相连、一奇一偶相连、两偶点相连即可。注意这样会造成重边,那么算出恰好有一条重边的方案数并减掉。由于是有序地考虑每条边,每次还要除以i。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 1010 #define P 10007 int n,m,k,degree[N],f[N][N],inv[N],ans,cnt; int C(int n,int m){return (n*(n-1)>>1)%P;} int main() { #ifndef ONLINE_JUDGE freopen("bzoj2169.in","r",stdin); freopen("bzoj2169.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(),k=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(); degree[x]^=1,degree[y]^=1; } for (int i=1;i<=n;i++) if (degree[i]) cnt++; inv[0]=1;inv[1]=1;for (int i=2;i<=k;i++) inv[i]=P-(P/i)*inv[P%i]%P; f[0][cnt]=1; for (int i=1;i<=k;i++) for (int j=0;j<=n;j++) f[i][j]=(f[i-1][j+2]*C(j+2,2)%P+f[i-1][j]*j%P*(n-j)%P+(j>=2?f[i-1][j-2]*C(n-j+2,2)%P:0)-(i>=2?f[i-2][j]*(C(n,2)-i+2)%P:0)+P)%P*inv[i]%P; cout<<f[k][0]; return 0; }