1 条题解
-
0
自动搬运
来自洛谷,原作者为

FZzzz
**搬运于
2025-08-24 22:27:00,当前版本为作者最后更新于2020-12-26 22:10:09,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
考虑最短路树,对于深度为 的某个点,深度小于 的点不能向其连边,至少有一个深度为 的点向其连边,对于其他点连向它的边没有限制。
这启发我们分层状压 dp。设 为,深度为 的点的集合为 ,深度小于等于 的点的集合为 ,只考虑连向深度大于 的点的边的限制,时,图满足条件的概率。
考虑转移。枚举深度为 的点的集合 ,则 内的点都不能向 内的点连边,且对于 内的每一个点, 内至少有一个点需要向其连边。dp 值即为每个这样的 符合条件的概率之和。
直接实现即可做到 的复杂度,因为这个 dp 实际上相当于枚举子集的子集。
对于每个 和 ,预处理 内的点都不向 内的点连边的概率,和对于每个 内的点 内的点至少有一个向其连边的概率。这部分可以在 至 不等的时间内完成。预处理后每次转移的复杂度降为 ,总时间复杂度为 。
需要进行一些卡常卡空间。
下面是我的最终代码,使用了滚动数组进行优化,空间 。理论上最好可以做到 空间。
#include<bits/stdc++.h> using namespace std; inline int readint(){ int x=0; bool f=0; char c=getchar(); while(!isdigit(c)&&c!='-') c=getchar(); if(c=='-'){ f=1; c=getchar(); } while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); } return f?-x:x; } const int maxn=12; int n,k; const int mod=998244353; int ksm(int a,int b){ int ans=1; while(b){ if(b%2==1) ans=1ll*ans*a%mod; a=1ll*a*a%mod; b/=2; } return ans; } inline void mul(int& x,int y){ x=1ll*x*y%mod; } int p[maxn+5][maxn+5]; int f[2][(1<<maxn)+5][(1<<maxn)+5]; int g[(1<<maxn)+5][(1<<maxn)+5],h[(1<<maxn)+5][(1<<maxn)+5]; int main(){ #ifdef LOCAL freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif n=readint(); k=readint(); for(int i=0;i<n*(n-1);i++){ int x,y; x=readint()-1; y=readint()-1; p[x][y]=readint(); mul(p[x][y],ksm(readint(),mod-2)); } int all=(1<<n)-1; for(int s1=0;s1<=all;s1++){ for(int i=0;i<n;i++) if(!(s1>>i&1)){ g[s1][1<<i]=1; for(int j=0;j<n;j++) if(s1>>j&1) mul(g[s1][1<<i],(1-p[j][i]+mod)%mod); } for(int s2=all^s1;s2;s2=(s2-1)&(all^s1)) if((s2&-s2)!=s2){ g[s1][s2]=1; for(int i=0;i<n;i++) if(s2>>i&1) mul(g[s1][s2],g[s1][1<<i]); } } for(int s1=0;s1<=all;s1++){ for(int i=0;i<n;i++) if(!(s1>>i&1)) h[s1][1<<i]=(1-g[s1][1<<i]+mod)%mod; for(int s2=all^s1;s2;s2=(s2-1)&(all^s1)) if((s2&-s2)!=s2){ h[s1][s2]=1; for(int i=0;i<n;i++) if(s2>>i&1) mul(h[s1][s2],h[s1][1<<i]); } } f[(k+1)%2][all][0]=1; for(int d=k;d>=0;d--) for(int s1=1;s1<=all;s1++){ f[d%2][s1][0]=s1==all; for(int s2=s1;s2;s2=(s2-1)&s1){ long long res=s1==all; for(int s3=all^s1;s3;s3=(s3-1)&(all^s1)) res+=1ll*f[!(d%2)][s1|s3][s3]*g[s1^s2][s3]%mod*h[s2][s3]%mod; f[d%2][s1][s2]=res%mod; } } printf("%d\n",f[0][1][1]); return 0; }
- 1
信息
- ID
- 6331
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者