题目:https://www.cnblogs.com/Juve/articles/11186805.html(密码是我的一个oj用户名)
solution:
反正我是想不出来。。。
题目大意就是要求出有多少个图删除一条边或加上一条边后成为一个连通的欧拉图
实际上答案等于有n个点的带标号连通的欧拉图数量*$C_{n}^{2}$,也就是我先数出所有的欧拉图数量,在这个欧拉图上删一条边或是加一条边得到合法方案,那么其实每一条边只会对应删或加,及$C_{n}^{2}$中选择。
数连通欧拉图则可以用容斥原理解决。
设连同欧拉图个数为fi,所有点度数均为偶数的图(不一定连通)为gi
则 gi=2$C_{i-1}^{2}$;
fi=gi-$\sum \limits_{j=1}^{i-1}$fi*gi-j*$C_{i-1}^{j-1}$;
组合数可以杨辉三角也可以求逆元
复杂度n2
杨辉三角版:
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define mod 1000000007
#define MAXN 4002
using namespace std;
ll n,g[MAXN],f[MAXN],C[MAXN][MAXN];
ll q_pow(ll a,ll b,ll p){
ll ans=1;
for(;b;b>>=1){
if(b&1) ans=ans*a%p;
a=a*a%p;
}
return ans%mod;
}
int main(){
scanf("%lld",&n);
for(ll i=0;i<=n+1;i++){
C[i][0]=1;
for(ll j=1;j<=i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
//for(ll i=1;i<=n;i++)
// for(ll j=1;j<i;j++)
// cout<<C[i][j]<<endl;
for(ll i=1;i<=n;i++){
f[i]=g[i]=q_pow(2,C[i-1][2],mod)%mod;
for(ll j=1;j<i;j++){
f[i]=(f[i]-f[j]*g[i-j]%mod*C[i-1][j-1]%mod+mod)%mod;
}
}
printf("%lld\n",f[n]*C[n][2]%mod);
return 0;
}
逆元版:
1 #include<cstdio> 2 #define p 1000000007 3 using namespace std; 4 int n; 5 long long g[2005],f[2005],fac[2005]; 6 inline long long qpow(long long a,long long b){register long long ans=1;a%=p;while(b){if(b&1)ans=ans*a%p;a=a*a%p;b>>=1;}return ans;} 7 inline long long C(long long nn,long long k){if(k>nn)return 0;else return fac[nn]*(qpow(fac[k]*fac[nn-k]%p,p-2))%p;} 8 inline long long Lucas(long long a,long long b){if(b==0) return 1;return C(a%p,b%p)*Lucas(a/p,b/p)%p;} 9 inline void getchart(){fac[1]=fac[0]=1;for(register long long i=2;i<=n;i++) fac[i]=(fac[i-1]*i)%p;return ;} 10 int main() 11 { 12 scanf("%d",&n);getchart(); 13 for(register int i=1;i<=n;++i)g[i]=qpow(2,Lucas(i-1,2))%p; 14 for(register int i=1;i<=n;++i) 15 { 16 long long ll=0; 17 for(register int j=1;j<=i;++j) 18 ll=(ll+((f[j]*g[i-j]%p)*Lucas(i-1,j-1)%p))%p; 19 f[i]=((g[i]-ll)%p+p)%p; 20 } 21 long long ans=f[n]*Lucas(n,2)%p; 22 printf("%lld",ans); 23 return 0; 24 }