zoukankan      html  css  js  c++  java
  • 记忆化搜索

    直接上题:

    本题就是求在m的情况下,那些点能通过吃其他的点,强化自己然后留到最后(挺像大鱼吃小鱼的)。

    没错,这就是挂我暴力的题,本来50分的暴力,因为没开longl long只剩可怜的十几分,算了,长个教训吧!

    我们刚开始的思想就暴力呗!暴力检查每个点能否扩到最后,然后输出!

    显然非正解...

    显然最大的点一定是必胜点,那我们再深入思考,必胜点都有什么性质:假如a是必胜点,而b再加强一部分后能吃掉a,那b显然也一定是必胜点!

    之后我们再考虑一个点x可以没有m限制的区间,那就是左右两边第一个比m大的数。

    没有m,x依然可以在这个区间里随便吃,知道碰到第一个比他大的数,需要验证了。

    如果设想p,q分别为第一个比m大的数,如果p是必胜点,而x能吃掉p,那显然x也是必胜点;

    可如果p不是必胜点呢?x也一定不是必胜点,为什么呢?因为p比x大而检查p时也一定加上x的那个区间,但p不是必胜点,则x也一定不是必胜点了。

    这样一个数的判断依赖于左右两个点的判断,即想知道x,必须知道p,q;这样搞一个记忆化搜索,就可以O(n)求解了。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const ll N=8100000;
    ll n,m,a[N],vis[N],l[N],r[N],top,maxx,sum[N];
    struct zhan
    {
        ll s,id;
    };
    zhan q[N];
    inline ll read()
    {
        ll x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)){if(x=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    inline void put(ll x)
    {
        if(x<0) putchar('-'),x=-x;
        if(x>9) put(x/10);
        putchar(x%10+'0');
    }
    inline void dfs(int x)
    {
        ll ans=sum[r[x]-1]-sum[l[x]];
        if(l[x]!=0&&ans+m>=a[l[x]])
        {
            if(!vis[l[x]]) dfs(l[x]);
            if(vis[l[x]]==1) vis[x]=1;
        }
        if(r[x]!=n+1&&ans+m>=a[r[x]])
        {
            if(!vis[r[x]]) dfs(r[x]);
            if(vis[r[x]]==1) vis[x]=1;
        }
        if(!vis[x]) vis[x]=-1;
        return ;
    }
    int main()
    {
        freopen("game.in","r",stdin);
        freopen("game.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=n;i++) a[i]=read(),maxx=max(maxx,a[i]),sum[i]=sum[i-1]+a[i];
        a[0]=a[n+1]=1e18;
        q[++top].s=a[0];q[top].id=0;
        for(int i=1;i<=n;i++)
        {
            if(a[i]==maxx) vis[i]=1;
            while(top&&a[i]>=q[top].s) top--;
            l[i]=q[top].id;
            q[++top].s=a[i];q[top].id=i;
        }
        top=0;q[++top].s=a[n+1];q[top].id=n+1;
        for(int i=n;i>=1;i--)
        {
            while(top&&a[i]>=q[top].s) top--;
            r[i]=q[top].id;
            q[++top].s=a[i];q[top].id=i;
        }
        for(int i=1;i<=n;i++) if(!vis[i]) dfs(i); 
        for(int i=1;i<=n;i++) if(vis[i]==1) put(i),putchar(' ');
        return 0;
    } 
  • 相关阅读:
    实用小工具 -- 国家地区IP段范围查询工具
    JAVA学习笔记--ClassLoader
    Apache HttpClient之fluent API的使用
    JAVA学习笔记--初探hash与map
    JAVA学习笔记--赋值(“=”)
    JAVA学习笔记--方法中的参数调用是引用调用or值调用
    修改host,访问指定服务器
    VueJS基础框架代码介绍
    Mac下通过npm安装webpack 、vuejs,以及引入jquery、bootstrap等(初稿)
    SSH配置与修改
  • 原文地址:https://www.cnblogs.com/gcfer/p/11548792.html
Copyright © 2011-2022 走看看