Bus Routes HDU - 5552 [NTT][cayley定理][CDQ分治][計數問題][DP]
Bus Routes HDU - 5552
Tags: NTT cayley定理 CDQ分治 計數問題 DP
Bus Routes HDU - 5552
題意
求有n個點的無向帶環聯通圖的m染色方案。
分析
考慮帶環聯通圖其實就是聯通圖總數-樹總數。
而聯通圖總數有是圖減去不聯通圖的數量。
那麼就設
f[n]表示n個點的聯通圖總數
g[n]表示n個點的圖總數
h[n]表示n個點的樹總數
然後g和h的式子比較好想。
對於h,根據cayley定理的應用,可以知道n個有標誌頂點的樹的數目等於
對於g,假設不管一條邊連或不連都計,那麼一共有
然後來考慮f。
考慮節點1所在的聯通塊的大小。那麼有
就和之前CDQ分治+fft的轉移差不多了。
code
#include<bits/stdc++.h>
#define mo 152076289
#define ll long long
using namespace std;
void read(int &x){
x=0; char c=getchar();
for (;c<48;c=getchar());
for (;c>47;c=getchar())x=(x<<1)+(x<<3)+(c^48);
}
ll ksm(ll a,ll b){
ll res=1;
for (;b;b>>=1){
if (b&1)res=res*a%mo;
a=a*a%mo;
}
return res;
}
#define M 20005
int rev[M];
struct NTT{
ll a[M];
ll &operator[](int i){
return a[i];
}
void solve(int n,int DFT){
register int i,j,k,m;
ll l,r,w,wn;
for (i=0;i<n;i++)if (rev[i]<i)swap(a[rev[i]],a[i]);
for (m=1;m<n;m<<=1){
k=(m<<1);
w=1;
wn=ksm(106,(mo-1)/k);
if (DFT){
wn=ksm(wn,mo-2);
}
for (i=0;i<m;i++){
for (j=i;j<n;j+=k){
l=a[j]; r=a[j+m];
a[j]=(l+w*r%mo)%mo;
a[j+m]=(l-w*r%mo+mo)%mo;
}
w=w*wn%mo;
}
}
if (DFT){
ll Chu=ksm(n,mo-2);
for (i=0;i<n;i++)a[i]=a[i]*Chu%mo;
}
}
void clear(int n){
for (int i=0;i<n;i++)a[i]=0;
}
}A,B;
ll f[M],g[M],h[M],jiecheng[M],chu[M];
void solve(int l,int r){
if (l==r){
f[l]=(g[l]-jiecheng[l-1]*f[l]%mo+mo)%mo;
return ;
}
int mid=(l+r)>>1,len=r-l+1,i,k;
solve(l,mid);
for (k=1;k<len;k<<=1);
for (i=0;i<k;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(k>>1));
A.clear(k); B.clear(k);
for (i=l;i<=mid;i++){
A[i-l]=f[i]*chu[i-1]%mo;
}
for (i=1;l+i<=r;i++){
B[i]=g[i]*chu[i]%mo;
}
A.solve(k,0); B.solve(k,0);
for (i=0;i<k;i++)A[i]=(A[i]*B[i])%mo;
A.solve(k,1);
for (i=mid+1;i<=r;i++){
f[i]=(f[i]+A[i-l])%mo;
}
solve(mid+1,r);
}
int main(){
// freopen("1.in","r",stdin);
int T,n,m,i,Ca;
jiecheng[0]=1;
for (i=1;i<M;i++)jiecheng[i]=jiecheng[i-1]*i%mo;
chu[M-1]=ksm(jiecheng[M-1],mo-2);
for (i=M-2;i>=0;i--)chu[i]=chu[i+1]*(i+1)%mo;
read(T);
for (Ca=1;Ca<=T;Ca++){
read(n); read(m);
for (i=1;i<=n;i++){
f[i]=0;
g[i]=ksm(m+1,1ll*i*(i-1)/2);
if (i==1)h[i]=1;
else h[i]=ksm(i,i-2)*ksm(m,i-1)%mo;
}
solve(1,n);
printf("Case #%d: %lld\n",Ca,(f[n]-h[n]+mo)%mo);
}
return 0;
}