传送门
提供一个不太一样的容斥做法。
首先容易发现答案只和每个点到 1 号点的奇偶最短路有关,可以先 求出来。
然后考虑枚举距离 ,计算有多少个 K 元组的距离为 。不妨设 为奇数,那么条件就是:
- 每个点的奇最短路的最大值为 ;
- 存在一个点的偶最短路 。
考虑怎么快速维护。对于每一张图,我们求出能到走到的奇偶最短路的最大值
我们把图分成两部分,一部分是 ,另一部分是 。
对于第一部分,不存在满足第一个条件的点,而且对于所有 的 ,这张图的满足第二个条件的点数量不会变,贡献很好维护。
对于第二部分,我们遍历所有满足条件的图,维护 表示是否满足第一个条件,是否满足第二个条件的方案数。我们需要知道对于每一张图,有多少个点满足奇最短路的为 ,有多少个点满足奇最短路的不超过 ,有多少个点满足奇最短路不超过 且偶最短路 ,这些信息都可以 求出。最终转移是一个或卷积。这一部分复杂度是 的。
总复杂度 。
代码:
int K;
int p1[N<<1],p2[N<<1];
struct Graph{
int n,m,cnt,maxn;
vector<int>h,ver,nxt,dis[2],t,d,c,pre;
inline void add_edge(int x,int y){cnt++;ver[cnt]=y;nxt[cnt]=h[x];h[x]=cnt;}
inline void init(){
n=read(),m=read();
h.resize(n+1),ver.resize(2*m+1),nxt.resize(2*m+1),dis[0].resize(n+1),dis[1].resize(n+1);
for(int i=1;i<=n;i++)dis[0][i]=dis[1][i]=mod;
for(int i=1;i<=m;i++){
int x=read(),y=read();
add_edge(x,y),add_edge(y,x);
}
queue<int>q;
dis[0][1]=0;
q.push(2);
while(!q.empty()){
int x=q.front()>>1,k=q.front()&1;
q.pop();
for(int i=h[x];i;i=nxt[i]){
int y=ver[i];
if(dis[k^1][y]>dis[k][x]+1){
dis[k^1][y]=dis[k][x]+1;
q.push((y<<1)|(k^1));
}
}
}
for(int i=1;i<=n;i++){
if(dis[0][i]!=mod)maxn=max(maxn,dis[0][i]);
if(dis[1][i]!=mod)maxn=max(maxn,dis[1][i]);
}
t.resize(maxn+1),d.resize(maxn+1),c.resize(maxn+3),pre.resize(maxn+1);
for(int i=1;i<=n;i++){
if(dis[0][i]<dis[1][i]){
d[dis[0][i]]++;
c[dis[0][i]]++;
if(dis[1][i]!=mod)c[dis[1][i]+1]--;
}
if(dis[1][i]<dis[0][i]){
d[dis[1][i]]++;
c[dis[1][i]]++;
if(dis[0][i]!=mod)c[dis[0][i]+1]--;
}
if(dis[0][i]!=mod)t[dis[0][i]]++;
if(dis[1][i]!=mod)t[dis[1][i]]++;
}
for(int i=0;i<=maxn;i++){
pre[i]=t[i];
if(i>1)pre[i]+=pre[i-2];
}
for(int i=2;i<=maxn+2;i++)c[i]+=c[i-2];
p1[maxn+2]=1ll*p1[maxn+2]*pre[maxn]%mod;
p2[maxn+2]=1ll*p2[maxn+2]*dec(pre[maxn],c[maxn+2])%mod;
p1[maxn+1]=1ll*p1[maxn+1]*(maxn?pre[maxn-1]:0)%mod;
p2[maxn+1]=1ll*p2[maxn+1]*dec(maxn?pre[maxn-1]:0,c[maxn+1])%mod;
}
}G[N];
vector<int>hav[N],q;
int maxd;
int f[4],g[4],a[4],ans;
int main(){
K=read();
for(int i=0;i<=200003;i++)p1[i]=p2[i]=1;
for(int i=1;i<=K;i++){
G[i].init();
hav[G[i].maxn].push_back(i);
maxd=max(maxd,G[i].maxn);
}
for(int i=2;i<=maxd;i++)p1[i]=1ll*p1[i]*p1[i-2]%mod,p2[i]=1ll*p2[i]*p2[i-2]%mod;
for(int i=maxd;i;i--){
for(auto j:hav[i])q.push_back(j);
memset(f,0,sizeof(f)),memset(g,0,sizeof(g));
g[0]=p2[i];g[1]=dec(p1[i],p2[i]);
for(auto j:q){
a[0]=G[j].pre[i]-G[j].t[i]-G[j].c[i]+G[j].d[i],a[1]=G[j].c[i]-G[j].d[i],a[2]=G[j].t[i]-G[j].d[i],a[3]=G[j].d[i];
memset(f,0,sizeof(f));
for(int i=0;i<4;i++){
for(int j=0;j<4;j++)add(f[i|j],1ll*g[i]*a[j]%mod);
}
swap(f,g);
}
add(ans,1ll*g[3]*i%mod);
}
cout<<ans<<endl;
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】