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;
}

原文地址:https://www.cnblogs.com/bztMinamoto/p/10246448.html

时间: 2024-08-26 19:37:27

uoj#279. 【UTR #2】题目交流通道(容斥+数数)的相关文章

【UTR #2】[UOJ#278]题目排列顺序 [UOJ#279]题目交流通道 [UOJ#280]题目难度提升

[UOJ#278][UTR #2]题目排列顺序 试题描述 "又要出题了." 宇宙出题中心主任 -- 吉米多出题斯基,坐在办公桌前策划即将到来的 UOI. 这场比赛有 n 道题,吉米多出题斯基需要决定这些题目的难度,然后再在汪洋大海中寻找符合该难度的题目. 题目的难度可以用一个 1 到 n 的排列 a1,-,an 表示,其中 ai 表示第 i 道题目在这 n 道题目中是第 ai 简单的题目,即恰有 ai?1 道题目比第 i 道题目简单. 经验丰富的吉米多出题斯基早就悟出了一种科学地决定难

uoj279题目交流通道(dp)

题目大意: 神犇星球有 \(n\) 座小城.对于任意两座小城 \(v,u\)\((v≠u)\),吉米多出题斯基想在 \(v,u\) 之间建立一个传送时间为 \(w(v,u)\)的无向传送通道,其中 \(w(v,u)\) 为不超过 \(k\) 的非负整数.建成后,神犇星球的居民可从一座小城出发经过一个或若干个传送通道到达另一座小城交流题目,花费的时间为所有经过的传送通道的传送时间之和. 吉米多出题斯基还没有决定每一个传送通道的传送时间取值,只是对于任意两座小城 \(v,u\),决定了从 \(v\)

HDU 6053 TrickGCD 容斥

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6053 题意: 给你序列a,让你构造序列b,要求 1<=b[i]<=a[i],且b序列的gcd>=2.问你方案数. 思路: 容易想到的就是我们枚举整个序列的gcd,然后a[i]/gcd就是i位置能够填的数的个数,然后每个位置累积就能得到数列为gcd时的方案数. 最后容斥一下累加就是答案.但是最大gcd可以是100000和明显这样做n^2,会超时. 那么我们把a[i]/gcd的放在一起,然后用

UOJ #214 合唱队形 (概率期望计数、DP、Min-Max容斥)

9个月的心头大恨终于切掉了!!!! 非常好的一道题,不知为何uoj上被点了70个差评. 题目链接: http://uoj.ac/problem/214 题目大意: 请自行阅读. 题解: 官方题解讲得相当清楚,这里补充一下自己的一些理解. 首先来看\(O(2^{n-m}\times poly(n,m))\)的做法. 一种理解方式是官方题解. 设\(s\)为总共的课程个数(\(n\)个字符串的总长度),\(p(S)\)表示结尾位置为集合\(S\)的串全部匹配一共需要完成多少个不同的课程.设\(f(t

POJ 2773 Happy 2006 二分+容斥(入门

题目链接:点击打开链接 题意: 输入n ,k 求与n互质的第k个数(这个数可能>n) 思路: solve(mid)表示[1,mid]中有多少个和n互质,然后二分一下最小的mid 使得互质个数==k solve(x) 实现: 与n互质的个数=所有数-与n不互质的数=所有数-(与n有一个因子-与n有2个因子的+与n有3个因子的) 状压n的因子个数,然后根据上面的公式容斥得到. #include <stdio.h> #include <iostream> #include <

POJ 2773 Happy 2006 (分解质因数+容斥+二分 或 欧几里德算法应用)

Happy 2006 Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 10309   Accepted: 3566 Description Two positive integers are said to be relatively prime to each other if the Great Common Divisor (GCD) is 1. For instance, 1, 3, 5, 7, 9...are a

hdu1695:数论+容斥

题目大意: 求x属于[1,b]和 y属于[1,d]的 gcd(x,y)=k 的方案数 题解: 观察发现 gcd()=k 不好处理,想到将x=x/k,y=y/k 后 gcd(x,y)=1.. 即问题转化为求区间 [1,b/k]和 [1,d/k]的互质数对个数 由于题目规定 (x,y)和(y,x)是同一种,所以我们可以规定 x<y,,然后只需对每一个y求出比他小的即可 公共部分可以通过欧拉函数快速求出.. 非公共部分就不行了.. 所以就分解质因数,用容斥的方法求了 #include <iostre

uva 10542 - Hyper-drive(容斥)

题目链接:uva 10542 - Hyper-drive 题目大意:给定n维空间的线段,问说线段经过几个格子. 解题思路:对于线段可以将一点移动至原点,变成 (0,0)到(a,b)这条线段,以二维为例,每次会从一个格子移动到另一个格子,可以是x+1坐标,也可以是y+1,所以总的应该是a+b-1,扣除掉x+1,y+1的情况gcd(a,b)-1 (原点).映射成n维就要用容斥原理计算结果. /*********************** * (0, 0, 0, ...) -> (a, b, c,

【BZOJ4927】第一题 双指针+DP(容斥?)

[BZOJ4927]第一题 Description 给定n根直的木棍,要从中选出6根木棍,满足:能用这6根木棍拼 出一个正方形.注意木棍不能弯折.问方案数. 正方形:四条边都相等.四个角都是直角的四边形. Input 第一行一个整数n. 第二行包含n个整数ai,代表每根木棍的长度. n ≤ 5000, 1 ≤ ai ≤ 10^7 Output 一行一个整数,代表方案数. Sample Input 8 4 5 1 5 1 9 4 5 Sample Output 3 题解:这...这不是沈阳集训的原