A
题意:求有多少无向图加一条边或删一条边后是有欧拉回路的连通图。
首先,这种图一定是有两个奇数度点的,然后它的操作方式、得到的欧拉图是唯一的,那么对于一个欧拉图,对于它已经存在的边,删去;对于它不存在的边,加上,都可以得到一组解。所以答案就是欧拉回路数×C2n×Cn2。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=2010;
const int inf=2147483647;
const int mod=1000000007;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,f[Maxn],F[Maxn],C[Maxn][Maxn];
void pre()
{
C[0][0]=1;
for(int i=1;i<=n;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
int Pow(int x,int y)
{
if(!y)return 1;
if(y==1)return x;
int t=Pow(x,y>>1),re=(LL)t*t%mod;
if(y&1)re=(LL)re*x%mod;
return re;
}
int main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
n=read();
pre();
f[1]=1;
for(int i=1;i<=n;i++)F[i]=Pow(2,C[i-1][2]);
for(int i=2;i<=n;i++)
{
f[i]=F[i];
for(int j=1;j<i;j++)
f[i]=(f[i]-(LL)C[i-1][j-1]*f[j]%mod*F[i-j]%mod+mod)%mod;
}
printf("%d",(LL)f[n]*C[n][2]%mod);
}
C
题意:
是不是看到这些乱七八糟的式子就要转化模型往上靠啊,这题就是先转化模型:nn种颜色的球,每种有不同的个,共有mm个,要求每种颜色球的号球必须在这种颜色的第一位。若我们固定11号球颜色的出现顺序,那么方案数就为,sisi为aiai的后缀和,为什么是这样呢?若没有任何限制,方案数显然是m!m!,但是,第一个球为固定颜色的11号球概率为,所以要先除掉mm,即,然后去掉所有颜色与它相同的球,剩下m−a1m−a1个球,为固定颜色的11号球概率为,即除掉sn−1sn−1……以此类推就得到这个式子,但是题目中是不除掉s1s1的,也就是不要求最后一种颜色的11号球必须出现在这种颜色的第一位。
至此我们已经完成了模型的转换,接下来就是计数问题。考虑容斥,枚举最后一种颜色为,第一次出现位置为pospos,后面至少有jj种颜色,后面的种颜色共有tt个球,那么有下面的式子
其中组合数是从后面的位置中选出jj种颜色以及的球的位置的方案数,后面的阶乘就是排列方式,除去的就是保证11号球必须在最前面,因为对于一种颜色的排列,号球在前面就是(ai−1)!(ai−1)!,即ai!aiai!ai,然后后面乘的两个alastalast,一个是不必除去alastalast而乘回来的,一个是表示枚举lastlast的哪个球放在最前面。但是仅有这样是不够的,还需要做一个背包,表示选取哪jj种颜色,共个到后面,背包的时候不需要记录选了多少种颜色,只需有记录其奇偶性即可,因为容斥的时候偶数的系数都是11,奇数的系数都是。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=60;
const int Maxm=1010;
const int inf=2147483647;
const int mod=1000000007;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
void upd(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int n,m=0,a[Maxn],C[Maxm][Maxm],inv[Maxm],fac[Maxm],g[Maxm];
void pre()
{
C[0][0]=1;
for(int i=1;i<=m;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++)
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
inv[0]=inv[1]=1;
for(int i=2;i<=m;i++)inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
fac[0]=1;
for(int i=1;i<=m;i++)fac[i]=(LL)fac[i-1]*i%mod;
for(int i=1;i<=m;i++)
{
g[i]=0;
for(int j=0;j<m;j++)g[i]=(g[i]+C[j][i-1])%mod;
}
}
int f[2][2][Maxm];//f[i][j][k]前i种(滚动)选j种(只需j的奇偶性)和为k
int main()
{
freopen("comb.in","r",stdin);
freopen("comb.out","w",stdout);
n=read();
a[0]=0;
for(int i=1;i<=n;i++)a[i]=read(),m+=a[i];
pre();
if(n==1)return printf("%d",fac[a[1]]),0;
int s=1,ans=0;
for(int i=1;i<=n;i++)s=(LL)s*inv[a[i]]%mod;
for(int last=1;last<=n;last++)
{
int tmp=(LL)s*a[last]%mod*a[last]%mod;
int now=0,sum=0;
memset(f,0,sizeof(f));
f[0][0][a[last]]=1;sum=a[last];
for(int i=0;i<n;i++)
{
sum+=a[i];
if(i==last)sum-=a[i];
if(i!=last-1)
{
now^=1;
memset(f[now],0,sizeof(f[now]));
for(int j=0;j<2;j++)
{
for(int k=0;k<=sum;k++)
if(f[now^1][j][k])
upd(f[now][j][k],f[now^1][j][k]),upd(f[now][j^1][k+a[i+1]],f[now^1][j][k]);
}
}
else
{
now^=1;
memset(f[now],0,sizeof(f[now]));
for(int j=0;j<2;j++)
{
for(int k=0;k<=sum;k++)
if(f[now^1][j][k])
upd(f[now][j][k],f[now^1][j][k]);
}
}
}
for(int c=a[last];c<=m;c++)
ans=(ans+(LL)fac[c-1]*fac[m-c]%mod*tmp%mod*f[now][0][c]%mod*g[c]%mod)%mod,
ans=(ans-(LL)fac[c-1]*fac[m-c]%mod*tmp%mod*f[now][1][c]%mod*g[c]%mod+mod)%mod;
}
printf("%d",ans);
}