T1:这题很简单。
把所有边按频率排序,枚举选边的区间,然后用并查集维护加边就可以了。
T2:这一题是一个复杂的上下界网络流+动态加边。
首先我们建立源点和汇点sd、td,然后从sd向所有i连流量限制为(0,inf),费用为in[i]的边(简称(0,inf,in[i]),下同)。然后从i向td连(0,inf,out[i])。这两种边表示i可以随时向sd或td流流量以减少或增加自身的流量,但是要话费in或out的费用。
如果i的left为负,那么就i向td连(-left,-left,0),否则sd向i连(left,left,0)。而对于原图的一条边(x,y,a,b,down,up),我们就把它拆成a+b,3a+b,5a+b……那么我们就能表示出所有流量的情况了。
对于这一个图,跑一遍有上下界的费用流,跑出来的就是答案。
注意:实际上,一条x、y的最开始的边不是a+b,而是以down为流量的费用。而且我们要在网络流过程中不断调整x、y的费用,防止出错。因为我们是优先选a+b、再3a+b……以此类推。
至于有上下界的网络流,参考我写的“上下界网络流”这篇博客。
T3:首先我们要推出一个式子,设f[i]表示n=i时的答案,那么f[i]=2^C(i,2)-sum(f[j]*C(i-1,j-1)*2^C(i-j,2)),(1<=j<=i-1)。
这条式子的意思就是用总的方案数-不合法的方案数。总的方案数就是2^C(i,2)。至于不合法的方案数我们就枚举一个i的子点集,设大小为j,并且我们规定1号点在选出来的集合里面(防止重复计算),那么保证j大小的点集为联通块的方案数是f[j],从i个点中选j个点并且要包含1号点的方案数为C(i-1,j-1),最后剩下的i-j的点之间可以随便连边(反正这已经是一个不联通图了),那么我们就得出了上面这一条式子。
但计算这条式子的时间复杂度是n^2的。所以我们化简一下:
f[i]=2^C(i,2)-sum(f[j]*C(i-1,j-1)*2^C(i-j,2))
=2^C(i,2)-sum(f[j]*(i-1)!/(j-1)!/(i-j)!*2^C(i-j,2))
然后把1/(j-i)!与f[j]放在一起,1/(i-j)!与2^C(i-j,2)放在一起,(i-1)!提出来,那么原式就变成了
f[i]=2^(i,2)-(i-1)!*sum(f[j]/(j-1)!*2^C(i-j,2)/(i-j)!)。
设F[i]=f[i]/(i-1)!,G[i]=2^C(i,2)/i!,接着把上面式子同除(i-1)!,那么就得到了
F[i]=2^(i,2)/(i-1)!-sum(F[j]*G[i-j]),这显然就是一个卷积的形式。
我们的目的是求F(G是可以预处理出来的),但是我们又不能直接用NTT做,因为更新后面F要用到前面的F,所以我们考虑用分治NTT。
所谓的分治NTT就是每次计算l~mid的F对mid+1~r的贡献。
注意:1、当前l~r的区间只能用l~mid的F乘某些G去给mid+1~r的F贡献。不在mid+1~r区间里的F是不能被当前l~mid贡献的。这样做是为了防止重复计算。
2、“某些G”的具体范围是1~r-l+1,因为F[x]*G[y]是对F[x+y]贡献的,所以我们用l~mid的F去给mid+1~r做贡献,G的取值范围就是1~r-l+1。
下面贴一下代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define ll long long
#define MAXN 520010
ll a[MAXN],b[MAXN],F[MAXN],G[MAXN],jc[MAXN],sum[MAXN],rev[MAXN],mod=1004535809,bit,s,n,g=3,ans;
ll sqr(ll x,ll y)
{
ll w=y,j=x%mod,s=1;
while(w>=1)
{
if(w%2==1)s=(s*j)%mod;
j=(j*j)%mod;
w/=2;
}
return s;
}
int getrev()
{
ll i;
for(i=0;i<s;i++)rev[i]=((rev[i>>1]>>1)|((i&1)<<(bit-1)));
}
int NTT(ll *a,ll inv)
{
ll i,j,step,k,x,y,wn,wnk,t;
for(i=0;i<s;i++)
if(i<rev[i]){t=a[i];a[i]=a[rev[i]];a[rev[i]]=t;}
for(step=1;step<s;step*=2)
{
if(inv==1)wn=sqr(g,(mod-1)/(step*2));
else wn=sqr(sqr(g,(mod-1)/(step*2)),mod-2);
for(j=0;j<s;j=j+step*2)
{
wnk=1;
for(k=j;k<j+step;k++)
{
x=a[k];y=wnk*a[k+step]%mod;
a[k]=(x+y)%mod;a[k+step]=(x-y+mod)%mod;
wnk=(wnk*wn)%mod;
}
}
}
}
int work()
{
ll i,v;
getrev();
NTT(a,1);NTT(b,1);
for(i=0;i<s;i++)a[i]=a[i]*b[i]%mod;
NTT(a,-1);
v=sqr(s,mod-2);
for(i=0;i<s;i++)a[i]=a[i]*v%mod;
}
int dg(ll l,ll r)
{
ll i,mid=(l+r)/2,left,right;
if(l==r)
{
if(l!=1)F[l]=(sqr((ll)2,l*(l-1)/2)*sqr(jc[l-1],mod-2)%mod-sum[l]+mod)%mod;
else F[l]=1;
return 0;
}
dg(l,mid);
left=1;right=r-l+1;
s=1;bit=0;
while(s<right-left+1)s*=2,bit++;
for(i=0;i<s;i++)a[i]=0,b[i]=0;
for(i=l;i<=mid;i++)a[i-l]=F[i];
for(i=left;i<=right;i++)b[i-left]=G[i];
for(i=mid-l+1;i<s;i++)a[i]=0;
for(i=right-left+1;i<s;i++)b[i]=0;
work();
for(i=0;i<s;i++)
if(i+l+left>=mid+1&&i+l+left<=r)sum[i+l+left]=(sum[i+l+left]+a[i])%mod;
dg(mid+1,r);
}
int main()
{
ll i,j;
scanf("%lld",&n);
ans=n;n=1;
while(n<ans)n*=2;
jc[0]=1;for(i=1;i<=n*2;i++)jc[i]=(jc[i-1]*i)%mod;
G[1]=1;
for(i=2;i<=n*2;i++)G[i]=sqr((ll)2,i*(i-1)/2)*sqr(jc[i],mod-2)%mod;
dg(1,n);
printf("%lld",F[ans]*jc[ans-1]%mod);
}