UOJ279 题目交流通道

来源:互联网 发布:pink cat动作数据下载 编辑:程序博客网 时间:2024/06/06 07:44

定好了难度,雄心勃勃的吉米多出题斯基开始寻找智慧的神犇星球的居民出题。

然而吉米多出题斯基没有料到,神犇星球的居民告诉吉米多出题斯基:“今年神犇星球经济不景气,大家都想宅在家里,哪有心思出来出题呢?”

为了挽救这一局面,吉米多出题斯基决定为神犇星球建一些高速传送通道促进该星球各地区之间交流题目。

神犇星球有 nn 座小城。对于任意两座小城 v,uv,u(v≠uv≠u),吉米多出题斯基想在 v,uv,u 之间建立一个传送时间为
w(v,u)w(v,u) 的无向传送通道,其中 w(v,u)w(v,u) 为不超过 kk
的非负整数。建成后,神犇星球的居民可从一座小城出发经过一个或若干个传送通道到达另一座小城交流题目,花费的时间为所有经过的传送通道的传送时间之和。

吉米多出题斯基还没有决定每一个传送通道的传送时间取值,只是对于任意两座小城 v,uv,u,决定了从 vv 出发到达 uu
的最短时间要恰好等于 d(v,u)d(v,u)。但吉米多出题斯基日理万机,于是他找到了你 ——
风璃殇做不出题耶维奇,请你帮助吉米多出题斯基数一数有多少种不同的满足条件的传送通道建设方案吧!

由于方案数可能很大,你只用输出方案数对
998244353998244353(7×17×223+17×17×223+1,一个质数)取模后的结果。 输入

第一行两个整数 n,kn,k。保证 n≥1,k≥0n≥1,k≥0。

接下来 nn 行,每行有 nn 个非负整数,第 ii 行的 第 jj 个数表示 d(i,j)d(i,j) 的值。 输出

输出一行,一个整数,表示方案数对 998244353998244353 取模的结果。如果无解,则方案数为 00。

如果没有为零的d的话,只需要对于所有的i,j寻找x使得d[i][x]+d[x][j]=d[i][j],如果找到的话e(i,j)就有kd[i][j]+1种取法,否则只有1种取法。
有零的话先用并查集把相互之间为零的缩成一块,块相互之间的情况同上。内部的话,设g[i]表示i个点内部的总方案数,f[i]表示i个点,相互之间为零的方案数。那么g[i]=(k+1)i(i1)/2。对于f求非法情况,枚举其中某一点x所在互相为零的块大小jf[i]=g[i]n1j=1Cj1i1f[j]g[ij](k+1)j(ij)
还要大力check一下非法情况。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define LL long longconst int mod=998244353;int f[410],g[410],d[410][410],c[410][410],fa[410],size[410],n,k;int find(int x){    return x==fa[x]?x:fa[x]=find(fa[x]);}int pow(int base,int p){    int ret=1;    for (;p;p>>=1,base=(LL)base*base%mod)        if (p&1) ret=(LL)ret*base%mod;    return ret;}bool check(){    int i,j,x;    for (i=1;i<=n;i++)        if (d[i][i])            return 1;    for (i=1;i<=n;i++)        for (j=1;j<=n;j++)            if (d[i][j]!=d[j][i]||d[i][j]>k)                return 1;    for (i=1;i<=n;i++)        for (j=1;j<=n;j++)            for (x=1;x<=n;x++)                if (d[i][j]>d[i][x]+d[x][j])                    return 1;    return 0;}int main(){    int i,j,ans=1,flag,x;    scanf("%d%d",&n,&k);    for (i=1;i<=n;i++)        for (j=1;j<=n;j++)            scanf("%d",&d[i][j]);    if (check())    {        printf("0\n");        return 0;    }    c[0][0]=1;    for (i=1;i<=n;i++)        for (j=0;j<=i;j++)            c[i][j]=((j?c[i-1][j-1]:0)+c[i-1][j])%mod;    f[0]=g[0]=1;    for (i=1;i<=n;i++)    {        g[i]=f[i]=pow(k+1,i*(i-1)/2);        for (j=1;j<i;j++)            f[i]=(f[i]-(LL)f[j]*g[i-j]%mod*c[i-1][j-1]%mod*pow(k,j*(i-j))%mod+mod)%mod;    }    for (i=1;i<=n;i++) fa[i]=i;    for (i=1;i<=n;i++)        for (j=1;j<=n;j++)            if (!d[i][j])                fa[find(i)]=find(j);    for (i=1;i<=n;i++)        size[find(i)]++;    for (i=1;i<=n;i++)        if (fa[i]==i)            ans=(LL)ans*f[size[i]]%mod;    for (i=1;i<=n;i++) if (fa[i]==i)        for (j=i+1;j<=n;j++) if (fa[j]==j)        {            flag=0;            for (x=1;x<=n;x++)                if (fa[x]==x&&i!=x&&j!=x&&d[i][x]+d[x][j]==d[i][j])                {                    flag=1;                    break;                }            if (flag) ans=(LL)ans*pow(k-d[i][j]+1,size[i]*size[j])%mod;            else ans=(LL)ans*(pow(k-d[i][j]+1,size[i]*size[j])-pow(k-d[i][j],size[i]*size[j])+mod)%mod;        }    printf("%d\n",ans);}
0 0
原创粉丝点击