1. 程式人生 > >uoj#279. 【UTR #2】題目交流通道(容斥+數數)

uoj#279. 【UTR #2】題目交流通道(容斥+數數)

傳送門

先考慮無解的情況,為以下幾種:\(dis_{i,j}+dis_{j,k}<dis_{i,k}\)\(dis_{i,i}\neq 0\)\(dis_{i,j}\neq dis_{j,i}\)\(dis_{i,j}>K\)。先大力特判掉

然後來考慮沒有邊權為\(0\)的時候,把原圖中所有的邊分類,對於\((i,j)\),如果存在\(k\)使得\(dis_{i,k}+dis_{k,j}=dis_{i,j}\),那麼稱其為\(B\)類邊,否則為\(A\)類邊。顯然\(A\)類邊的權值就是\(dis_{i,j}\),因為從其他地方走權值都大於自己。然後大力猜想一發對於所有\(B\)

類邊,權值可以取\([dis_{i,j},K]\)之間的數,接下來證明它

因為存在一條路徑從\(i\)\(j\)且權值為\(dis_{i,j}\),那麼這條路徑\(F\)上的邊數大於等於\(2\),如果其上都是\(A\)類邊,那麼就算所有\(B\)取值為\(K\)也沒關係。那麼反證,假設其上有一條邊為\(B\)類邊,那麼這條\(B\)類邊也有對應一條與它權值相等的路徑\(G\)\(G\)不可能與\(F\)有任何一條邊重複,否則我們可以在\(F\)上不走那條\(B\)邊而是走\(G\),那麼少走了重複的那幾條邊,路徑權值會變小,與\(F\)是最短路矛盾

綜上,所有\(A\)類邊取值固定,\(B\)

類邊可以取\([dis_{i,j},K]\)之間的邊,判斷一下邊的型別,用乘法原理統計答案就好了

信心滿滿交上去結果只有\(30\)分,發現自己忘記考慮邊權為\(0\)的情況了

如果有邊權為\(0\),那麼我們可以把這兩個點縮成一個點,而且不難發現最短路為\(0\)是具有傳遞性的,所以我們可以把互相之間最短路為\(0\)的點縮到一起,記其中點的個數為\(size_i\),縮完點之後的圖就是沒有邊權為\(0\)的情況了

考慮一個連通塊內部,如果把\(0\)邊當成實邊,那麼\(0\)邊需要讓所有的點聯通,而其它的邊的取值無所謂。記\(f_i\)\(i\)個點的連通塊中\(0\)邊使所有點聯通的方案數,那麼有\[f_i=(K+1)^{C_{i}^2}-\sum_{j=1}^{i-1}K^{(i-j)\times j}(K+1)^{C_{i-j}^2}C_{i-1}^{j-1}f_j\]


上面的式子的意思就是,總共的方案減去不合法的方案,不合法的方案可以列舉與\(1\)同一個聯通快的點的大小\(j\),那麼內部的方案就是\(f_j\),然後\(j\)\(i-j\)之間的邊能為\(0\)\(i-j\)內部隨便連

上面是連通塊的貢獻,然後考慮邊的貢獻,設一條邊連線的兩個連通塊大小分別為\(i,j\),兩個連通塊之間的最短路長度為\(d\),如果這條邊是\(B\)類邊,那麼方案數就是\((K-d+1)^{i\times j}\),如果是\(A\)類邊,就是\((K-d+1)^{i\times j}-(K-d)^{i\times j}\)即合法的減去不合法的

然後就沒有然後了

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=505,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x=y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
    R int res=1;
    for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
    return res;
}
int a[N][N],vis[N][N],fa[N],f[N],fac[N],inv[N],sz[N];
int n,K,res=1;
inline int C(R int n,R int m){if(m>n)return 0;return mul(fac[n],mul(inv[m],inv[n-m]));}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
bool ck(){
    fp(i,1,n)if(a[i][i]!=0)return false;
    fp(i,1,n)fp(j,i+1,n){
        if(a[i][j]!=a[j][i])return false;
        if(a[i][j]>K)return false;
        fp(k,1,n)if(a[i][j]+a[j][k]<a[i][k])return false;
    }return true;
}
void init(){
    inv[0]=fac[0]=1;fp(i,1,n)fac[i]=mul(fac[i-1],i);
    inv[n]=ksm(fac[n],P-2);fd(i,n-1,1)inv[i]=mul(inv[i+1],i+1);
    fp(i,1,n)fa[i]=i;
    fp(i,1,n)fp(j,i+1,n)if(a[i][j]==0)fa[find(j)]=find(i);
    fp(i,1,n)++sz[find(i)];
    fp(i,1,n){
        f[i]=ksm(K+1,C(i,2));
        fp(j,1,i-1)f[i]=dec(f[i],1ll*ksm(K,j*(i-j))*ksm(K+1,C(i-j,2))%P*C(i-1,j-1)%P*f[j]%P);
    }
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read(),K=read();
    fp(i,1,n)fp(j,1,n)a[i][j]=read();
    if(!ck())return puts("0"),0;
    init();
    fp(i,1,n)find(i);
    fp(i,1,n)if(fa[i]==i)
        fp(j,i+1,n)if(fa[j]==j){
            bool flag=0;
            fp(k,1,n)if(fa[k]==k)
                if(k!=i&&k!=j&&a[i][k]+a[j][k]==a[i][j]){flag=1;break;}
            if(flag)res=mul(res,ksm(K-a[i][j]+1,sz[i]*sz[j]));
            else res=mul(res,dec(ksm(K-a[i][j]+1,sz[i]*sz[j]),ksm(K-a[i][j],sz[i]*sz[j])));
        }
    fp(i,1,n)if(find(i)==i)res=mul(res,f[sz[i]]);
    printf("%d\n",res);
    return 0;
}