題意:給定和集合,求出個點的「所有極大點雙連通分量的大小都在 內」的不同簡單無向連通圖的個數 模 。
道理我都懂,可爲啥我百度搜地靈殿ex終符一半都是cookie☆同人OI題
思路挺清奇的
首先注意題目中的點雙定義是不存在割點,也就是說只有兩個點的連通圖也是點雙
同時一個點可能屬於多個點雙
顯然要設出答案的EGF
因爲無向圖關係很複雜,所以我們要強行整點東西上去
設表示 個點 帶標號 有根 滿足題目條件 的方案數 的EGF
有根是指:每張圖欽定一個根,如果兩張圖邊完全相同但根不同也視爲不同的圖
其實就是乘一個
考慮怎麼表示出
對於一張有根圖,我們把根刪掉,這樣會出現多個連通塊
對於每個連通塊,會發現都會有若干點和根處於同一個點雙內
但是不會有不同連通塊的點處於同一點雙,因爲根結點刪去後它們分開了,與定義矛盾
考慮一個連通塊的情況
先考慮根結點所在的點雙大小,發現同一組點組成的點雙也有多種連邊方案
設表示個點構成的帶標號點雙個數
再設出滿足題目要求的點雙的EGF
因爲沒有跨連通塊,所以這個連通塊的點雙一定在內
然後將點雙中的所有邊刪掉,這樣點雙中的點兩兩間都不會連通 因爲如果連通,由於內部邊都斷完了,只能走外面的點,而經過的點都會在這個點雙內
也就是說,這個大連通塊被分成了若干小連通塊,且連通塊個數等於點雙的大小(不含根),小連通塊的根是原來的點雙中的點
這樣可以寫出一個大連通塊的EGF
也就是
注意:這個過程並沒有選出點雙中有哪些點,只是把連通塊中的點分組並將每組的根按點雙的方式連接起來
然後可以表示成任意個數連通塊組合再加上根
也就是
假設我們已經求出了,我們嘗試算出
設
即和互爲複合逆
而
顯然,所以可以算出,進而用拉格朗日反演算出
現在的問題是如何求
直接求不好求,考慮構造一個相似的問題用其他方法算一次,再把反推回來
那考慮減少限制 發現減掉在中的限制,也就是任意連通圖,我們也可以用這個思路計算
並且這是一道原題
直接取對數就可以輕鬆算出答案,豈不美哉?
好,我們仿(fu)照(zhi)這道題,算出任意無向連通圖的EGF ,並乘一個上個根
現在 已知了
設
相同的思路,得到
變一下可以得到
用拉格朗日反演算出……
拉個鬼啊,一次拉格朗日反演就是的,你要算出就要跑次,再怎麼也有了吧
但我們注意到有值的地方很少,而且下標和不超過,所以如果我們直接拉出就沒有複雜度問題啦
好,整理一下已知條件
閒着沒事把上面代到下面
(注:這裏爲了統一代碼改一下)
好多括號啊,拆掉裏面那個
停,我說一句
有個叫擴展拉格朗日反演的東西,長這樣:
證明的話在兩邊同時複合一個,並令,後面就一模一樣了
好繼續
我們強行構造上面的結論,令
這樣
就可以把算出來
現在只需要求出
由於
得到
並不需要手動算,除出來挪一下就可以了
把讀入的位置拉出來直接丟到的對應位置,然後推出即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <ctime>
#define MAXN 400005
using namespace std;
const int MOD=998244353;
inline int read()
{
int ans=0;
char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
typedef long long ll;
inline int add(const int& x,const int& y){return x+y>=MOD? x+y-MOD:x+y;}
inline int dec(const int& x,const int& y){return x<y? x-y+MOD:x-y;}
inline int qpow(int a,int p)
{
int ans=1;
while (p)
{
if (p&1) ans=(ll)ans*a%MOD;
a=(ll)a*a%MOD;p>>=1;
}
return ans;
}
#define inv(x) qpow(x,MOD-2)
int fac[MAXN],finv[MAXN];
int rt[2][24];
int l,r[MAXN];
inline void init(){for (int i=0;i<(1<<l);i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));}
inline void NTT(int* a,int type)
{
int lim=1<<l;
for (int i=0;i<lim;i++) if (i<r[i]) swap(a[i],a[r[i]]);
for (int L=0;L<l;L++)
{
int mid=1<<L,len=mid<<1,Wn=rt[type][L+1];
for (int s=0;s<lim;s+=len)
for (int k=0,w=1;k<mid;k++,w=(ll)w*Wn%MOD)
{
int x=a[s+k],y=(ll)w*a[s+mid+k]%MOD;
a[s+k]=add(x,y);a[s+mid+k]=dec(x,y);
}
}
if (type)
{
int t=inv(lim);
for (int i=0;i<lim;i++) a[i]=(ll)a[i]*t%MOD;
}
}
void getinv(int* A,int* B,int n)
{
static int f[MAXN],t[MAXN];
if (n==1) return (void)(*B=inv(*A));
getinv(A,t,(n+1)>>1);
for (l=0;(1<<l)<(n<<1);l++);
init();
for (int i=0;i<n;i++) f[i]=A[i];
for (int i=n;i<(1<<l);i++) f[i]=t[i]=0;
NTT(f,0);NTT(t,0);
for (int i=0;i<(1<<l);i++) B[i]=(ll)t[i]*dec(2,(ll)f[i]*t[i]%MOD)%MOD;
NTT(B,1);
for (int i=n;i<(1<<l);i++) B[i]=0;
}
inline void deriv(int* A,int* B,int n){for (int i=0;i<n-1;i++) B[i]=(ll)A[i+1]*(i+1)%MOD;B[n-1]=0;}
inline void integ(int* A,int* B,int n){for (int i=1;i<n;i++) B[i]=(ll)A[i-1]*fac[i-1]%MOD*finv[i]%MOD;B[0]=0;}
void getln(int* A,int* B,int n)
{
static int f[MAXN],g[MAXN];
deriv(A,f,n);getinv(A,g,n);
for (int i=n;i<(1<<l);i++) f[i]=g[i]=0;
NTT(f,0);NTT(g,0);
for (int i=0;i<(1<<l);i++) f[i]=(ll)f[i]*g[i]%MOD;
NTT(f,1);
integ(f,B,n);
for (int i=n;i<(1<<l);i++) B[i]=0;
}
void getexp(int* A,int* B,int n)
{
static int f[MAXN],g[MAXN];
if (n==1) return (void)(*B=1);
getexp(A,g,(n+1)>>1);getln(g,f,n);
for (int i=0;i<n;i++) f[i]=dec(A[i],f[i]);
++f[0];
for (int i=n;i<(1<<l);i++) f[i]=g[i]=0;
NTT(f,0);NTT(g,0);
for (int i=0;i<(1<<l);i++) B[i]=(ll)f[i]*g[i]%MOD;
NTT(B,1);
for (int i=n;i<(1<<l);i++) B[i]=0;
}
void getpow(int* A,int* B,int n,int k)
{
static int t[MAXN];
getln(A,t,n);
for (int i=0;i<n;i++) t[i]=(ll)t[i]*k%MOD;
getexp(t,B,n);
}
int G[MAXN],H[MAXN],dH[MAXN],A[MAXN],t[MAXN],f[MAXN];
int LangInv(int* F,int n,bool ex=false)
{
static int f[MAXN],g[MAXN];
for (int i=0;i<n;i++) f[i]=F[i+1];
f[n]=0;
getinv(f,g,n);
getpow(g,f,n,n);
int ans=0;
if (ex) for (int i=0;i<n;i++) ans=add(ans,(ll)dH[i]*f[n-i-1]%MOD);
else ans=f[n-1];
return (ll)ans*fac[n-1]%MOD*finv[n]%MOD;
}
time_t START;
int main()
{
fac[0]=1;
for (int i=1;i<MAXN;i++) fac[i]=(ll)fac[i-1]*i%MOD;
finv[MAXN-1]=inv(fac[MAXN-1]);
for (int i=MAXN-2;i>=0;i--) finv[i]=(ll)finv[i+1]*(i+1)%MOD;
rt[0][23]=qpow(3,119);rt[1][23]=inv(rt[0][23]);
for (int i=22;i>=0;i--)
{
rt[0][i]=(ll)rt[0][i+1]*rt[0][i+1]%MOD;
rt[1][i]=(ll)rt[1][i+1]*rt[1][i+1]%MOD;
}
int n=read();
for (int i=0;i<=n;i++) t[i]=(ll)qpow(2,((ll)i*(i-1)/2)%(MOD-1))*finv[i]%MOD;
getln(t,G,n+1);
for (int i=0;i<=n;i++) G[i]=(ll)G[i]*i%MOD;
for (int i=0;i<n;i++) t[i]=G[i+1];
t[n]=0;
getln(t,H,n+1);deriv(H,dH,n+1);
for (int s=read();s;s--)
{
int p=read()-1;
A[p]=LangInv(G,p,true);
}
getexp(A,t,n+1);getinv(t,A,n+1);
for (int i=1;i<=n;i++) f[i]=A[i-1];
f[0]=0;
printf("%d\n",(ll)LangInv(f,n)*fac[n-1]%MOD);
return 0;
}
P.S. 如果你用LOJ的C++(NOI) T成了狗,試試C++……