• D. Empty Graph #813 div2


    Problem - D - Codeforces

    题意是给你一组序列,编号1,2,3对应着点的编号,根据这个序列创建一个无向有权图。然后从点a到点b的权值就是对应在这个序列里面的[a,b]的最小值,然后找到所有从一个点到另外的一个点的最短路的权值最大。

    可以有不超过k次的操作:选择一个任意索引,使得a[i]=x(x∈[1,1e9])

    贪心 二分都可以写

    下面我说贪心的思路

    这题你要从图里面发现很多性质才可以把这个题写掉

    首先:图的最大权值必然是相邻的点的最小值,即min(a[i],a[i+1])

    证明:点al到ar的权值为[l,r]的最小权值,你在一个数组里面有个值最小,因为有这个值的存在,包含这个点的所有区间对应到所有的点的权值都是那个最小的数,为了方便起见,这个值也就是相邻的点的权值,整体上来看最大的权值必然是某个相邻的点的权值

    第二:这个题的本质是从a到b的最短路的最大值

    a到b可以有两种走法:这里定义一个最小值ax(在x的位置上)

    ①:a->b,这种情况在区间[a,b]上面没有这个ax,也就是没有整体的这一个最小值。就是a直接到b,这个遍历一遍就好,取路上的最小权值然后取max

    ②:a->x->b,在这一段路径上包含了ax,也就是最小值在这个区间上面,那这个a到b的权值也就是先可以a到x,然后x到b,所以这种情况的权值就是ax*2

    好,上面是两种可能的走法,如果k==0,那上面的就是答案了。

    现在开始使用k,就开始依据上面然后基于贪心的思想,开始进行最小值的最大化

    根据上面的第一种情况的表达式:maxn=max(maxn,min(a[i],a[i+1])

    第二种情况是尽可能的把最小值变大,然后ax*2

    一个是线性一个是平方,所以首选的是第二种:让最小值尽可能的变大

    怎么变大?就是把前k-1小的数变成正无穷,然后第k个数理应就是变化后的最小值

    刚刚说到前k-1小的数,把k-1次都留在操作最小值,然后第k次有两种选择:

    要么是继续操作最小值,要么是增加a->b,这里操作一次,也就是增加一次即可(第一种操作),多了没意义,反正都是取两者的最小值。就是取两者种的最小值,无论怎么变化,我们都可以把其中一个权值变成无穷大,然后取最大权值的那个就好

    1. #pragma GCC optimize(1)
    2. #pragma GCC optimize(2)
    3. #pragma GCC optimize(3,"Ofast","inline")
    4. #define IOS ios::sync_with_stdio(false), cin.tie(0);
    5. #include<iostream>
    6. #include<map>
    7. #include<set>
    8. #include<cstdio>
    9. #include<cstring>
    10. #include<vector>
    11. #include<stack>
    12. #include<algorithm>
    13. #include<cmath>
    14. #include<queue>
    15. #include<deque>
    16. using namespace std;
    17. #define int long long
    18. typedef long long LL;
    19. typedef pair<int,int> PAII;
    20. const int N=2e6+10,M=5050,INF=1e9,mod=1e9+7;
    21. int a[N],b[N];
    22. signed main(){
    23. //IOS;
    24. int T;
    25. //T=1;
    26. cin>>T;
    27. while(T--)
    28. {
    29. priority_queue<PAII,vector<PAII>,greater<PAII>> q;
    30. int n,k;
    31. cin>>n>>k;
    32. for(int i=1;i<=n;i++)
    33. {
    34. cin>>a[i];
    35. q.push({a[i],i});
    36. }
    37. for(int i=1;i<=k-1;i++)//这里操作k-1
    38. {
    39. auto t=q.top();
    40. q.pop();
    41. int pos=t.second;
    42. q.push({INF,pos});
    43. a[pos]=INF;
    44. }
    45. for(int i=1;i<=n;i++) b[i]=a[i];//b数组留最后一次操作过程量
    46. auto t=q.top();
    47. q.pop();
    48. int p1=t.second;
    49. q.push({INF,p1});
    50. a[p1]=INF;//a数组继续操作最小值
    51. int maxn=-1e18;
    52. for(int i=1;i<=n-1;i++) maxn=max(maxn,min(a[i],a[i+1]));
    53. sort(a+1,a+n+1);
    54. int res1=min(a[1]*2,maxn);
    55. sort(b+1,b+n+1);
    56. int res2=min(b[1]*2,b[n]);
    57. //这里b是把其中的一个变大,不管怎么样都是可以取到最大权值,所以这里不用具体实现增加过程量,直接是最大权值就好,也就是b[n]
    58. cout<<max(res1,res2)<<"\n";
    59. }
    60. return 0;
    61. }
    62. /*
    63. */

  • 相关阅读:
    对数据排序
    Linux下的web服务器搭建
    CSDN21天学习挑战赛之选择排序
    Oracle19c安装后,使用impdp导数,报错 ORA-01017:
    PCR检测试剂——博迈伦
    ZStack CEO 张鑫:让云计算在未来无人提及,又无处不在!
    Linux安装nginx详细步骤
    Redis 发布订阅
    软件设计模式系列之二十五——访问者模式
    动态规划算法
  • 原文地址:https://blog.csdn.net/m0_63305704/article/details/126919752