P13835 返夏 题解
哦哦哦毛毛虫坐火箭。
把每条边两端的点当作关键点,把环上每两个关键点之间的环缩成一条边,可以得到点数边数都是
求这张图的生成树数量显然用矩阵树定理,单次
常数太大了
mt19937 mt(chrono::system_clock().now().time_since_epoch().count());
cint N=1600,M=800;
cint mod=998244353;
int n,m;
int c[N+1];
map<int,int>mp;
int eu[M+1],ev[M+1];
int deg[N+1];
struct edge{
int to,val,nxt;
}E[(N+M)<<1|1];
int head[N+1];
int tot;
inline void add_edge(cint u,cint v,cint w)
{
E[++tot]={v,w,head[u]};
head[u]=tot;
E[++tot]={u,w,head[v]};
head[v]=tot;
((deg[u]+=w)>=mod)&&(deg[u]-=mod);
((deg[v]+=w)>=mod)&&(deg[v]-=mod);
}
int a[N<<1|1],sc[N<<1|1][N+1],base[N+1];
int detb;
inline int qpow(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=1ll*res*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return res;
}
int calc()
{
detb=1;
for(int i=1;i<n;++i)
{
sc[0][i]=mt()%mod;
base[i]=mt()%mod;
detb=1ll*detb*base[i]%mod;
}
for(int i=1;i<=(n<<1);++i)
{
for(int u=1;u<n;++u)
{
__int128 s=1ll*sc[i-1][u]*deg[u]%mod*base[u];
for(int j=head[u];j;j=E[j].nxt)
{
cint v=E[j].to;
s-=1ll*sc[i-1][v]*E[j].val%mod*base[v];
}
sc[i][u]=s%mod;
(sc[i][u]<0)&&(sc[i][u]+=mod);
}
}
for(int i=1;i<n;++i)base[i]=mt()%mod;
for(int i=0;i<=(n<<1);++i)
{
__int128 s=0;
for(int j=1;j<n;++j)
{
s+=1ll*sc[i][j]*base[j];
}
a[i]=s%mod;
}
vector<int>v,lstv;
int lst=-1,lstd=0;
for(int i=0;i<=(n<<1);++i)
{
__int128 sd=a[i];
for(int j=0;j<v.size();++j)
{
sd-=1ll*a[i-j-1]*v[j];
}
int d=sd%mod;
(d<0)&&(d+=mod);
if(!d)continue;
if(lst<0)
{
lst=i;
lstd=d;
v=vector<int>(i+1);
continue;
}
vector<int>u=v;
cint val=1ll*d*qpow(lstd,mod-2)%mod;
if(v.size()<lstv.size()+i-lst)v.resize(lstv.size()+i-lst);
((v[i-lst-1]+=val)>=mod)&&(v[i-lst-1]-=mod);
for(int j=0;j<lstv.size();++j)
{
v[i-lst+j]=(v[i-lst+j]-1ll*val*lstv[j])%mod;
(v[i-lst+j]<0)&&(v[i-lst+j]+=mod);
}
if((int)u.size()-i<(int)lstv.size()-lst)
{
lstv=u;
lst=i;
lstd=d;
}
}
for(int &x:v)x=(x?mod-x:0);
v.insert(v.begin(),1);
return 1ll*v[v.size()-1]*qpow(detb,mod-2)%mod*((n&1)?1:mod-1)%mod;
}
int rn;
void solve(cint m)
{
n=(m<<1);
for(int i=1;i<=m;++i)
{
c[i]=eu[i];
c[i+m]=ev[i];
}
sort(c+1,c+n+1);
n=0;
for(int i=1;i<=(m<<1);++i)
{
if(c[i]!=c[n])
{
swap(c[i],c[++n]);
}
}
mp.clear();
for(int i=1;i<=n;++i)mp[c[i]]=i;
tot=0;
for(int i=1;i<=n;++i)head[i]=deg[i]=0;
for(int i=1;i<n;++i)add_edge(i,i+1,qpow(c[i+1]-c[i],mod-2));
add_edge(1,n,qpow(rn-c[n]+c[1],mod-2));
int base=1;
for(int i=1;i<n;++i)base=1ll*base*(c[i+1]-c[i])%mod;
base=1ll*base*(rn-c[n]+c[1])%mod;
for(int i=1;i<=m;++i)
{
add_edge(mp[eu[i]],mp[ev[i]],1);
}
princh(1ll*calc()*base%mod,'\n');
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
rn=read();
m=read();
for(int i=1;i<=m;++i)
{
eu[i]=read();
ev[i]=read();
}
for(int i=1;i<=m;++i)solve(i);
return 0;
}