[关闭]
@xiaoziyao 2021-01-26T09:00:12.000000Z 字数 2021 阅读 981

CF332D Theft of Blueprints解题报告

解题报告


CF332D Theft of Blueprints解题报告

更好的阅读体验

题意

分析

比较好玩的一道题。

的情况

时,只存在个只包含一个单点的点集,我们直接枚举每个点,然后直接计算每个点连接的边的边权和,最后除以就好了,时间复杂度:

的情况

我们枚举每一个中间点,并枚举这个中间点的每一条边,那么不难发现这条边造成贡献当且仅当另一个点成为点集,且有一条边。设的度数为,这条边权值为,则这条边造成的贡献为

时间复杂度:

的情况

引理1:当时且满足上述条件时,原图任意两个结点都恰好有个公共相邻结点。
证明:
设原图内两点公共相邻结点数量为,那么有:
如果,那么这两个结点的公共相邻结点可以形成一个大小为的集合,且两个点都是中间点,不符合题意,故
如果,那么这两个点与它们公共相邻顶点构成的点集大小小于等于,取任意一个大小为的集合,满足为该集合的子集,则可以得到一个新的点,且与这两个点均存在一条边,也就是说两个点存在了一个新的公共相邻结点,故
因此,结论成立。


引理2:当时且满足上述条件时,原图包含一个个点的完全图。
证明:我们取任意相连的两点,不难找到一个包含的集合,它的中间点为,那么均存在一条边,同理寻找一个包含的集合中间点为,一直寻找到,不难发现这个点构成了一个个点的完全图。


引理3:当且满足上述条件时,仅个点的完全图满足条件。
证明:根据引理可得原图包含一个个点的完全图。根据引理又可得完全图中两点的公共顶点恰好为完全图内的其他点。
设原图存在一个不在完全图中的点,取一个包含完全图两点的点集,得到它的中间点为,且在完全图中。那么再取一个包含的点集,可得另一个中间点为,且在完全图中,那么存在公共顶点,而因为完全图总两点的公共顶点为完全图内的其他点,因此在完全图内,故不存在完全图外的点,即原图为一个个点的完全图。

知道了该图为个点的完全图,这道题就简单了。

我们考虑仅存在个不同的子集,那么很显然对于每一个子集,该子集外的点便为这个子集的中间点,也就是说每个点都会作为中间点计算一次,我们直接算所有点连接的所有边边权之和除以就好了。

时间复杂度:

代码

  1. #include<stdio.h>
  2. #include<vector>
  3. #define int long long
  4. using namespace std;
  5. const int maxn=2005;
  6. int n,k,ans;
  7. vector< pair<int,int> >v[maxn];
  8. signed main(){
  9. scanf("%lld%lld",&n,&k);
  10. for(int i=1;i<=n;i++)
  11. for(int j=i+1;j<=n;j++){
  12. int x;
  13. scanf("%lld",&x);
  14. if(x==-1)
  15. continue;
  16. v[i].push_back(make_pair(j,x));
  17. v[j].push_back(make_pair(i,x));
  18. }
  19. if(k==1){
  20. for(int i=1;i<=n;i++)
  21. ans+=v[i][0].second;
  22. printf("%lld\n",ans/n);
  23. return 0;
  24. }
  25. if(k==2){
  26. for(int i=1;i<=n;i++){
  27. int cnt=0,sum=0;
  28. for(int j=0;j<v[i].size();j++)
  29. cnt++,sum+=v[i][j].second;
  30. ans+=(cnt-1)*sum;
  31. }
  32. printf("%lld\n",ans/(n*(n-1)/2));
  33. return 0;
  34. }
  35. for(int i=1;i<=n;i++)
  36. for(int j=0;j<v[i].size();j++)
  37. ans+=v[i][j].second;
  38. printf("%lld\n",ans/n);
  39. return 0;
  40. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注