【链接】链接


【题意】


n个人从左到右站在一条直线上。每个人都有一个能力值g[i],然后每个人可以将相邻的一个人打败。
然后它的能力值能够增加相应的能力值(就是打败了的那个人的能力值).
A能够打败B的条件是g[A]+D>=g[B].
n-1次后,只会剩下一个人了。
问你最后的那一个人可能是谁。
输出所有可能的人的编号。

【题解】


设dfs(i),表示要找第i个人能不能成为最后的winner.
暴力做的话,肯定会超时的。
->O(N^2)的算法了。
于是我们寻求更快的方法。
我们维护以下两个东西,
l[i]和r[i].
l[i]表示的是最大的jj<i,且g[j]>g[i]的下标j.(如果没有就为0)
r[i]表示的是最小的jj>i,且g[j]>g[i]的下标j.(如果没有就为N)
这两个东西,能用一个单调递减的单调队列弄出来。
O(N)就能得到。
然后考虑某一个位置i;
我们想要获取第i个位置是不是可以成为最后的Winner.
设这个问题为dfs(i);
显然l[i]+1..r[i]-1这一段都是g[i]能够不用增加D就吃到的
那么。我们把i这个人的能力值tot加上sum[l[i]+1..r[i]-1] (前缀和就能搞出来);
接下来,看看,这个tot+D能不能大于等于g[ l[i] ];
如果可以的话,则这个问题就能转化为,求dfs(l[i])了.
也即,转化为l[i]能不能成为winner了
因为对于l[i]而言,l[i]+1..r[i]-1这一段,它是肯定能够吃掉的。
(因为g[ l[i]+1..r[i]-1 ]是比g[i]小的,而g[ l[i] ] > g[i])
那么也就说,从i点吃到r[i]-1点,再一直吃到l[i]点..
再想一下,如果我们在做dfs(l[i]),则肯定也会把g[ l[i]+1..r[i]-1 ]全都吃掉.
不就是等价的了吗?
也就是说,现在问题已经完全转化为l[i]这个点能不能成为最后的winner了
对于dfs(l[i]),还是一样的,在l[ l[i] ]+1..r[ l[i] ] -1之间的人,都会被吃掉。然后又+D看看能不能再往外扩展
可以的话,就又能转化为dfs( l[ l[i] ] -1)或dfs(r[ l[i] ] + 1)这两个问题了
直到l[i]==0且r[i]==N,则可以直接返回true.因为这是个最大的数了,肯定能吃掉所有的.
(且可以肯定,dfs(x)中的x是一直在增大的)
当然还可以试一下r[i].(如果tot+D>=g[ r[i] ]就可以再试一下r[i]);
因为同理也能从l[i]+1吃到r[i],然后转化为dfs(r[i])这个问题
只要l[i]和r[i]中的任意一个可以成为winner.
那么i就能成为winner.
且,因为l[i]的区间l[ l[i] ]..r[ l[i] ]区间肯定覆盖了l[i]..r[i]区间。所以不会出现环
考虑到上面的过程是一个递归的过程
且找过一次答案之后,答案就是确定的了。
有大量重复的子问题。
写一个记忆化搜索就可以了。
这是一个类似DAG的问题

UPD
l[i]和r[i]是i这个人必须要吃掉的人(因为都比它大),则我们必须要吃掉其中一个人才能继续吃
(这是必须要做的事情,必须这么贪心,算法的正确性没有问题);
一旦能够吃l[i]或r[i],会发现,问题能转化成求另外一个位置的问题,(只有那个位置可以,i的位置才可以,否则不行!)
那个问题,还是用相同的方法去做,即新的i,然后又去打败li或ri(必须打败),然后打败之后,有能转化为另外一个位置的问题,且会发现,递归的过程不会出现环,即dfs(x)->dfs(y),然后dfs(y)里面又要调用dfs(x)这样的情况,不会出现。因为
g[y]>g[x]总是成立的,所以我们调用的dfs(x)的g[x]是单调递增的,总会有出口的(l[i]..r[i]这个区间会越来越大,直到变成
[0..N]这个区间,也即x变成了最大的数字)

【错的次数】


0

【反思】


出现了重复的问题->考虑记忆化搜索
考虑动规。
重复的子问题。

【代码】

/*

*/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <iomanip>
#include <set>
#include <cstdlib>
#include <cmath>
#include <bitset>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define pb emplace_back
#define fi first
#define se second
#define ld long double
#define ms(x,y) memset(x,y,sizeof x)
#define ri(x) scanf("%d",&x)
#define rl(x) scanf("%lld",&x)
#define rs(x) scanf("%s",x)
#define rf(x) scnaf("%lf",&x)
#define oi(x) printf("%d",x)
#define ol(x) printf("%lld",x)
#define oc putchar(' ')
#define os(x) printf(x)
#define all(x) x.begin(),x.end()
#define Open() freopen("F:\\rush.txt","r",stdin)
#define Close() ios::sync_with_stdio(0)
#define sz(x) ((int) x.size())
#define ld long double typedef pair<int,int> pii;
typedef pair<LL,LL> pll; //mt19937 myrand(time(0));
//int get_rand(int n){return myrand()%n + 1;}
const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
const double pi = acos(-1.0);
const int N = 1e6; int n,d,l[N+10],r[N+10],dp[N+10];
LL sum[N+10];
pll a[N+10];
vector <pll> v;
vector <int> ans; int dfs(int x){
    if (dp[x]!=-1) return dp[x];
    if (l[x]==-1 && r[x]==-1){
        return dp[x] = true;
    }
    LL temp = a[x].fi;
    if (l[x]==-1)
        temp += sum[x-1];
    else
        temp += sum[x-1] - sum[l[x]];
    if (r[x]==-1)
        temp += sum[n] - sum[x];
    else
        temp += sum[r[x]-1] - sum[x];
    if (l[x]!=-1 && temp + d >= a[l[x]].fi && dfs(l[x]))
        return dp[x] = true;
    if (r[x]!=-1 && temp + d >= a[r[x]].fi && dfs(r[x]))
        return dp[x] = true;
    return dp[x] = false;
} int main(){
    ms(dp,255);
    //Open();
    //Close();
    ri(n),ri(d);
    rep1(i,1,n){
        LL x;
        rl(x);
        a[i].fi = x,a[i].se = i;
        sum[i] = sum[i-1] + x;
    }     rep1(i,1,n){
        while (!v.empty() && v.back().fi<=a[i].fi){
                v.pop_back();
            }
        //v.back() > a[i].fi
        if (v.empty()){
            l[i] = -1;
        }else{
            l[i] = v.back().se;
        }
        v.pb(a[i]);
    }     v.clear();
    rep2(i,n,1){
        while (!v.empty() && v.back().fi<=a[i].fi){
                v.pop_back();
            }
        //v.back() > a[i].fi
        if (v.empty()){
            r[i] = -1;
        }else{
            r[i] = v.back().se;
        }
        v.pb(a[i]);
    }     rep1(i,1,n)
        if (dfs(i)){
            ans.pb(i);
        }
    rep1(i,0,sz(ans)-1){
        oi(ans[i]);
        if (i==sz(ans)-1)
            puts("");
        else
            oc;
    }
    return 0;
}

【CS Round #46 (Div. 1.5) E】Ultimate Orbs的更多相关文章

  1. 【CS Round #46 (Div. 1.5) C】Set Subtraction

    [链接]h在这里写链接 [题意] 一开始有n个数字,然后有一个数字X,把每个数字都减去X,又生成N个新的数字. 然后把这2*N个数字混在一起. 告诉你这2*N个数字是什么.让你复原出原来的N个数字,以 ...

  2. 【CS Round #46 (Div. 1.5) B】Letters Deque

    [链接]h在这里写链接 [题意] 让你把一个正方形A竖直或水平翻转. 问你翻转一次能不能把A翻转成B [题解] 有说一定要恰好为1次. 并不是说A和B相同就一定不行. [错的次数] 2 [反思] 自己 ...

  3. 【CS Round #46 (Div. 1.5) A】Letters Deque

    [链接]h在这里写链接 [题意] 在这里写题意 [题解] string类模拟 [错的次数] 0 [反思] 在这了写反思 [代码] /* */ #include <cstdio> #incl ...

  4. 【CS Round #36 (Div. 2 only) A】Bicycle Rental

    [题目链接]:https://csacademy.com/contest/round-36/task/bicycle-rental/ [题意] 让你从n辆车中选一辆车; 每一辆车有3个属性 1.到达车 ...

  5. 【CS Round #37 (Div. 2 only) D】Reconstruct Graph

    [Link]:https://csacademy.com/contest/round-37/task/reconstruct-graph/statement/ [Description] 给你一张图; ...

  6. 【CS Round #37 (Div. 2 only) B】Group Split

    [Link]:https://csacademy.com/contest/round-37/task/group-split/ [Description] 让你把一个数分成两个数a.b的和; (a,b ...

  7. 【CS Round #37 (Div. 2 only) A】Boring Number

    [Link]:https://csacademy.com/contest/round-37/task/boring-number/ [Description] 让你找离平均数最近的一个数的下标; [S ...

  8. 【CS Round #39 (Div. 2 only) D】Seven-segment Display

    [Link]:https://csacademy.com/contest/round-39/task/seven-segment-display/ [Description] 0..9各自有一个数字, ...

  9. 【CS Round #39 (Div. 2 only) C】Reconstruct Sum

    [Link]:https://csacademy.com/contest/round-39/task/reconstruct-sum/ [Description] 给你一个数字S; 让你找有多少对A, ...

随机推荐

  1. 【Henu ACM Round#15 E】 A and B and Lecture Rooms

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 最近公共祖先. (树上倍增 一开始统计出每个子树的节点个数_size[i] 如果x和y相同. 那么直接输出n. 否则求出x和y的最近 ...

  2. MySpring dataSource从配置文件获取

    大神就不看了.本篇是一个人笔记. 原来的数据库配置文件是写死的. 看代码:Mybatis的配置文件 <bean id="dataSource" class="org ...

  3. Java io流的学习

    近期几天细致学了Java的io流.本来是打算看视频通过视频来学习的.但是后来发现事实上视频看不怎么懂也感觉不是非常easy上手,所以就通过百度和api文档学习了Java的io流 io流能够有两个分类, ...

  4. es63块级作用域

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. js插件---Amaze UI dialog如何使用

    js插件---Amaze UI dialog如何使用 一.总结 一句话总结:别人给你列出来的参考手册照着用先 1.在哪里去找插件参考资料或者使用手册(一般位置找不到的时候)? github上面啊,非常 ...

  6. 【深入篇】Andorid中常用的控件及属性

    TextView  android:autoLink 设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web/email/phone/map/al ...

  7. SQL去除字符串内部的空格

    ''空字符 char(13) ' ' 空格字符 char(32) 去除内部空格 去除内部空格(二) sql语句实现换行,回车 制表符: CHAR(9) 换行符: CHAR(10) 回车符: CHAR( ...

  8. java(内部类)

    内部类: 一个类定义在另外一个类的内部就称作为内部类. 内部类的类别: 1.成员内部类: 2.局部内部类: 1.成员内部类: 成员内部类的访问方式: 方式一:在成员内部类的外侧提供一个方法创建内部类的 ...

  9. HDU——T 2594 Simpsons’ Hidden Talents

    http://acm.hdu.edu.cn/showproblem.php?pid=2594 Time Limit: 2000/1000 MS (Java/Others)    Memory Limi ...

  10. cogs P1578【模板】 次小生成树初级练习题

    1578. 次小生成树初级练习题 ☆   输入文件:mst2.in   输出文件:mst2.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 求严格次小生成树 [输入格式 ...