• [atARC116F]Deque Game


    假设两个操作者分别为$A$和$B$,其中$A$希望最大、$B$希望最小

    (并不默认$A$为整局游戏的先手,仅是最终的结果考虑$A$为先手时)

    记第$i$个队列第$j$个元素为$a_{i,j}$(其中$1le ile k,1le jle n_{i}$)

    特判$n_{i}=1$的队列,直接把队列中的元素加到最后的和中即可

    当$k=1$时且$A$为先手时,答案为(为了方便,均省略$n_{1}$和$a_{1,i}$中的1)
    $$
    egin{cases}max(a_{frac{n}{2}},a_{frac{n}{2}+1})&(nequiv 0(mod 2))\min(a_{frac{n+1}{2}},max(a_{frac{n-1}{2}},a_{frac{n+3}{2}}))&(nequiv 1(mod 2))end{cases}
    $$
    若$B$为先手,将$max$和$min$交换(改为另一种)即可

    (正确性把所有情况一起按照$n$归纳即可)

    下面,考虑若$A$可以选择哪一方为先手,此时$A$会选择谁(仍在$k=1$的基础上)

    对两种情况分别讨论,不难得到$A$会在$nequiv 0(mod 2)$时选择$A$,$nequiv 1(mod 2)$时选择$B$

    同理,$B$会在$nequiv 0(mod 2)$时选择$B$,$nequiv 1(mod 2)$时选择$A$

    通俗的来说,即序列长度为偶数时双方会去操作,而奇数时双方希望对方先操作

    (关于这个结论,仅仅是方便思考,并不能证明下面做法的正确性)

    由此,当所有序列长度都为奇数,显然当先手操作某一个序列,后手都跟着操作即可,独立求出每一个序列的$A$为先手的答案并求和即可

    对于长度为偶数的序列,双方的策略即先手选择一个长度为偶数的序列,后手选择另一个长度为偶数的序列,不断选择直至没有偶数的序列,最后根据奇偶性即可判定谁先选长度为奇数的序列

    关于选择哪一个,显然按照两种情况的差值排序后贪心选择即可

    总复杂度为$o(klog k)$,可以通过

    (正确性把所有情况一起按照$sum_{i=1}^{k}n_{i}$归纳即可)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 200005
     4 vector<int>v,a[N];
     5 int n,x,s,m[N];
     6 long long ans;
     7 int main(){
     8     scanf("%d",&n);
     9     for(int i=1;i<=n;i++){
    10         scanf("%d",&m[i]);
    11         if (m[i]==1){
    12             scanf("%d",&x);
    13             ans+=x;
    14             i--,n--;
    15             continue;
    16         }
    17         for(int j=1;j<=m[i];j++){
    18             scanf("%d",&x);
    19             a[i].push_back(x);
    20         }
    21         if (m[i]%2==0)s++;
    22     }
    23     if (s%2==0){
    24         for(int i=1;i<=n;i++){
    25             if (m[i]&1)ans+=min(a[i][m[i]/2],max(a[i][m[i]/2-1],a[i][m[i]/2+1]));
    26             else{
    27                 int x=a[i][m[i]/2-1],y=a[i][m[i]/2];//最中间两个 
    28                 ans+=min(x,y);
    29                 if (m[i]==2)v.push_back(abs(x-y));
    30                 else v.push_back(max(min(x,max(a[i][m[i]/2-2],y)),min(y,max(x,a[i][m[i]/2+1])))-min(x,y));
    31             }
    32         }
    33         sort(v.begin(),v.end());
    34         for(int i=1;i<s;i+=2)ans+=v[i];
    35         printf("%lld",ans);
    36         return 0;
    37     }
    38     for(int i=1;i<=n;i++){
    39         if (m[i]&1)ans+=max(a[i][m[i]/2],min(a[i][m[i]/2-1],a[i][m[i]/2+1]));
    40         else{
    41             int x=a[i][m[i]/2-1],y=a[i][m[i]/2];
    42             ans+=max(x,y);
    43             if (m[i]==2)v.push_back(-abs(x-y));
    44             else v.push_back(min(max(x,min(a[i][m[i]/2-2],y)),max(y,min(x,a[i][m[i]/2+1])))-max(x,y));
    45         }
    46     }
    47     sort(v.begin(),v.end());
    48     for(int i=1;i<s;i+=2)ans+=v[i];
    49     printf("%lld",ans);
    50 } 
    View Code
  • 相关阅读:
    Android view显示在软键盘上方
    ListView子项点击无反应的解决办法
    adb for mac
    Android文件的流操作工具类
    Linux之间配置SSH互信(SSH免密码登录)
    最简单的Linux虚拟机磁盘扩容方法
    Grunt + Bower—前端构建利器
    Microsoft Office 2016 简体中文 Vol 版镜像下载(Pro Plus、Visio、Project 下载)
    如何在windows下安装GIT
    如何在Crystal框架项目中内置启动MetaQ服务?
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14876401.html
Copyright © 2020-2023  润新知