• [bzoj4391] [Usaco2015 dec]High Card Low Card 贪心 线段树


    ~~~题面~~~

    题解:

      观察到以决策点为分界线,以点数大的赢为比较方式的游戏都是它的前缀,反之以点数小的赢为比较方式的都是它的后缀,也就是答案是由两段答案拼凑起来的。

      如果不考虑判断胜负的条件的变化,则有一个比较容易发现的贪心:

      设f[i]为从1开始到i位, 比较方式为点数大的获胜,最多能赢几局。

      那么为了使答案尽可能优,每次我们都会在剩余牌中找到点数大于对方的 最小的牌,然后出掉。

      同理,设g[i]为从n开始到i位,比较方式为点数小的获胜,最多能赢几局,

      则每次都在剩余牌中选择点数小于对方的,最大的牌出掉,这样可以使得答案尽可能优。

      最后的答案则是max(f[i] + g[i + 1]);

      那么为什么这样一定就是合法的呢?

        首先最优性应该是可以理解的,那么唯一会导致不合法的情况就是至少一张牌a,在两边的决策中都出现了(即被出掉了2次)。对于这种情况,任意一张a出掉了2次,因为游戏次数=牌数,所以必然还对应着一张b没有被出过。那么如果b > a,则用b来代替f[i]中的a一定合法,因为f[i]是点数大的获胜。反之,b < a, 则用b来代替g[i + 1]中的a一定合法,因为g[i]是点数小的获胜。

      于是为了求出这2个数组,我们需要一个可以支持查询前驱后继和删除的数据结构。

      你可以选择set,splay,线段树等等。

      这里我因为不会用set,懒得写splay,所以选择了值域线段树。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 100100
      5 #define ac 1001000
      6 #define inf INT_MAX
      7 
      8 int n, w, go, ans;
      9 int tree[ac], maxn[ac], minn[ac], l[ac], r[ac];
     10 int s[AC], f[AC], g[AC];
     11 bool z[AC];//记录哪些牌在对方手里
     12 
     13 inline int read()
     14 {
     15     int x = 0;char c = getchar();
     16     while(c > '9' || c < '0') c = getchar();
     17     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
     18     return x;
     19 }
     20 
     21 inline void upmax(int &a, int b)
     22 {
     23     if(b > a) a = b;
     24 }
     25 
     26 void pre()
     27 {
     28     n = read();
     29     for(R i = 1; i <= n; i ++) s[i] = read(), z[s[i]] = true;
     30 }
     31 
     32 inline void update(int x)
     33 {
     34     int ll = x * 2, rr = ll + 1;
     35     tree[x] = tree[ll] + tree[rr];
     36     maxn[x] = max(maxn[ll], maxn[rr]);
     37     minn[x] = min(minn[ll], minn[rr]);
     38 }
     39 
     40 void build(int x, int ll, int rr)
     41 {
     42     l[x] = ll, r[x] = rr;
     43     if(ll == rr) 
     44     {
     45         if(!z[ll]) 
     46             tree[x] = 1, maxn[x] = ll, minn[x] = ll;
     47         else minn[x] = inf;
     48         return ;
     49     }
     50     int mid = (ll + rr) >> 1;
     51     build(x * 2, ll, mid);
     52     build(x * 2 + 1, mid + 1, rr);
     53     update(x);
     54 }
     55 
     56 void last(int x)//前驱
     57 {
     58     if(minn[x] > w) return ; 
     59     if(l[x] == r[x])
     60     {
     61         tree[x] = maxn[x] = 0, minn[x] = inf, go = 1;
     62         return ;
     63     }
     64     if(minn[x * 2 + 1] < w) last(x * 2 + 1);
     65     else last(x * 2);
     66     update(x);
     67 }
     68 
     69 void Next(int x)//后继
     70 {
     71     if(maxn[x] < w) return ;
     72     if(l[x] == r[x])
     73     {
     74         tree[x] = maxn[x] = 0, minn[x] = inf, go = 1;
     75         return ;
     76     }
     77     if(maxn[x * 2] > w) Next(x * 2);
     78     else Next(x * 2 + 1);
     79     update(x);
     80 }
     81 
     82 void work()
     83 {
     84     build(1, 1, 2 * n);
     85     for(R i = 1; i <= n; i ++)
     86     {
     87         w = s[i], go = 0, Next(1);
     88         f[i] = f[i - 1] + go;
     89     }
     90     build(1, 1, 2 * n);
     91     for(R i = n; i; i --)
     92     {
     93         w = s[i], go = 0, last(1);
     94         g[i] = g[i + 1] + go;
     95     }
     96     /*for(int i = 1; i <= n; i ++) printf("%d ", f[i]);
     97     printf("
    ");
     98     for(int i = 1; i <= n; i ++) printf("%d ", g[i]);
     99     printf("
    ");*/
    100     for(R i = 0; i <= n; i ++) upmax(ans, f[i] + g[i + 1]);
    101     printf("%d
    ", ans);
    102 }
    103 
    104 int main()
    105 {
    106     freopen("in.in", "r", stdin);
    107     pre();
    108     work();
    109     fclose(stdin);
    110     return 0;
    111 }
    View Code
  • 相关阅读:
    .Net简单上传与下载
    C语言课程设计——电影院订票系统
    Git学习笔记
    浅析RPO漏洞攻击原理
    网络1911、1912 C语言第5次作业循环结构 批改总结
    MOCTF WriteUp
    Visual Studio 2019/2017 安装使用教程(快速上手版)
    南京邮电大学网络攻防平台——WriteUp(持续更新)
    java大作业博客购物车
    .Net Framework 2.0 的System.Data.SqlClient.AddWithValue()方法
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9807654.html
Copyright © 2020-2023  润新知