@xiaoziyao
2021-01-26T09:00:12.000000Z
字数 2021
阅读 981
解题报告
CF332D Theft of Blueprints解题报告
比较好玩的一道题。
时,只存在个只包含一个单点的点集,我们直接枚举每个点,然后直接计算每个点连接的边的边权和,最后除以就好了,时间复杂度:。
我们枚举每一个中间点,并枚举这个中间点的每一条边,那么不难发现这条边造成贡献当且仅当另一个点与成为点集,且与有一条边。设的度数为,这条边权值为,则这条边造成的贡献为。
时间复杂度:。
引理1:当时且满足上述条件时,原图任意两个结点都恰好有个公共相邻结点。
证明:
设原图内两点公共相邻结点数量为,那么有:
如果,那么这两个结点的公共相邻结点可以形成一个大小为的集合,且两个点都是中间点,不符合题意,故。
如果,那么这两个点与它们公共相邻顶点构成的点集大小小于等于,取任意一个大小为的集合,满足为该集合的子集,则可以得到一个新的点,且与这两个点均存在一条边,也就是说两个点存在了一个新的公共相邻结点,故。
因此,结论成立。
引理2:当时且满足上述条件时,原图包含一个个点的完全图。
证明:我们取任意相连的两点,不难找到一个包含的集合,它的中间点为,那么与,与均存在一条边,同理寻找一个包含的集合中间点为,一直寻找到,不难发现这个点构成了一个个点的完全图。
引理3:当且满足上述条件时,仅个点的完全图满足条件。
证明:根据引理可得原图包含一个个点的完全图。根据引理又可得完全图中两点的公共顶点恰好为完全图内的其他点。
设原图存在一个不在完全图中的点,取一个包含完全图两点与的点集,得到它的中间点为,且在完全图中。那么再取一个包含的点集,可得另一个中间点为,且在完全图中,那么与存在公共顶点,而因为完全图总两点的公共顶点为完全图内的其他点,因此在完全图内,故不存在完全图外的点,即原图为一个个点的完全图。
知道了该图为个点的完全图,这道题就简单了。
我们考虑仅存在个不同的子集,那么很显然对于每一个子集,该子集外的点便为这个子集的中间点,也就是说每个点都会作为中间点计算一次,我们直接算所有点连接的所有边边权之和除以就好了。
时间复杂度:。
#include<stdio.h>
#include<vector>
#define int long long
using namespace std;
const int maxn=2005;
int n,k,ans;
vector< pair<int,int> >v[maxn];
signed main(){
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++){
int x;
scanf("%lld",&x);
if(x==-1)
continue;
v[i].push_back(make_pair(j,x));
v[j].push_back(make_pair(i,x));
}
if(k==1){
for(int i=1;i<=n;i++)
ans+=v[i][0].second;
printf("%lld\n",ans/n);
return 0;
}
if(k==2){
for(int i=1;i<=n;i++){
int cnt=0,sum=0;
for(int j=0;j<v[i].size();j++)
cnt++,sum+=v[i][j].second;
ans+=(cnt-1)*sum;
}
printf("%lld\n",ans/(n*(n-1)/2));
return 0;
}
for(int i=1;i<=n;i++)
for(int j=0;j<v[i].size();j++)
ans+=v[i][j].second;
printf("%lld\n",ans/n);
return 0;
}