uoj279 题目交流通道

题目:告诉你每两个点之间的最短路距离。构造每条边边权<=m的无向完全图。求有多少种不同边权的图满足最短路限制?n<=400.

标程:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 typedef long long ll;
 6 const int mod=998244353;
 7 const int N=405;
 8 int n,a[N][N],c[N][N],g[N],f[N],sz[N],h[N],ans,m;
 9 bool ok()
10 {
11     for (int i=1;i<=n;i++) if (a[i][i]) return 0;
12     for (int i=1;i<=n;i++)
13       for (int j=i+1;j<=n;j++) if (a[i][j]!=a[j][i]||a[i][j]>m) return 0;
14     for (int i=1;i<=n;i++)
15       for (int j=i+1;j<=n;j++)
16         for (int k=1;k<=n;k++)
17           if ((ll)a[i][k]+a[k][j]<a[i][j]) return 0;
18     return 1;
19 }
20 int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
21 int ksm(int x,int y)
22 {
23     int res=1;
24     while (y) {if (y&1) res=(ll)res*x%mod; x=(ll)x*x%mod; y>>=1;}
25     return res;
26 }
27 void init()
28 {
29     for (int i=0;i<=n;i++) c[i][0]=1;
30     for (int i=1;i<=n;i++)
31       for (int j=1;j<=i;j++) c[i][j]=((ll)c[i-1][j]+c[i-1][j-1])%mod;
32 }
33 int main()
34 {
35     scanf("%d%d",&n,&m);init(); ans=1;
36     for (int i=1;i<=n;i++)  
37       for (int j=1;j<=n;j++) scanf("%d",&a[i][j]);
38     if (!ok()) return puts("0"),0;
39     for (int i=1;i<=n;i++) f[i]=i;
40     for (int i=1;i<=n;i++) 
41       for (int j=i+1;j<=n;j++) if (!a[i][j]) f[find(i)]=find(j);
42     for (int i=1;i<=n;i++) sz[find(i)]++;
43     for (int i=1;i<=n;i++) 
44      if (f[i]==i)
45       for (int j=i+1,k;j<=n;j++)
46         if (f[j]==j)
47         {
48             for (k=1;k<=n;k++)
49             if (f[k]==k&&k!=i&&k!=j&&a[i][j]==(ll)a[i][k]+a[k][j]) break;
50           int ts=sz[i]*sz[j];
51            if (k<=n) ans=(ll)ans*ksm(m-a[i][j]+1,ts)%mod;
52             else ans=(ll)ans*(ksm(m-a[i][j]+1,ts)-ksm(m-a[i][j],ts)+mod)%mod;
53          }    
54    for (int i=1;i<=n;i++) 
55    {
56       g[i]=h[i]=ksm(m+1,i*(i-1)/2);//h[i]表示i个点不保证mst=0的方案数。g[i]表示包含1点和其他i-1个点中保证有mst=0的方案数。
57       for (int j=1;j<i;j++)
58         g[i]=(ll)(g[i]-(ll)g[j]*h[i-j]%mod*c[i-1][j-1]%mod*ksm(m,j*(i-j))%mod+mod)%mod;
59     }
60     for (int i=1;i<=n;i++) if (f[i]==i) ans=(ll)ans*g[sz[i]]%mod;
61     printf("%d
",ans);
62    return 0;
63 }

易错点:1.不要漏取模。

题目:性质+并查集+容斥dp

特判一下不合法(无解)的情况。

考虑一张没有0边的图(如果有0边的话ijk三角形中会有两条边被判作无用),当a[i,j]=a[i,k]+a[k,j]时,a[i,j]这条边可以在a[i,j]~m中任取,这条边是没有贡献的。

考虑特殊的0边,如果有一些点对的距离为0,那么就用并查集缩起来,那么这个图就变成了若干个连通块,每个连通块中的点对之间的距离都是0。

所以就可以在连通块之间做没有0边的情况(两个连通块之间的所有边应该都是相等的,一条边的贡献可以直接统计sz[i]*sz[j]次),在连通块内用套路容斥出mst=0的边权方案数。

复杂度O(n^3).

原文地址:https://www.cnblogs.com/Scx117/p/8708281.html