zoukankan      html  css  js  c++  java
  • ACM/ICPC 2018亚洲区预选赛北京赛站网络赛D-80 Days--------树状数组

     题意就是说1-N个城市为一个环,最开始你手里有C块钱,问从1->N这些城市中,选择任意一个,然后按照顺序绕环一圈,进入每个城市会有a[i]元钱,出来每个城市会有b[i]个城市,问是否能保证经过每个城市,钱都不会能为0,如果可以请输出最小的那个   

    这题最开始队员想错了。。。后来思路就乱了,整理一下思路,你会发现,其实我们要求的就是从i到n+i的前缀和最小值一定要大于c。 

    那么如何解决这个问题呢???

    你会发现,其实我们只需要算一个影响就行,假如最小的点的在ID,那么前面i->ID的数肯定小,对吧???

    如果ID<0,我从i到id,依次减去这个点的贡献,直到ID>=0,那么由于i到ID,ID到N这些数肯定是比ID大的,因此我们只需要看尾部增加的值的是否小于0并且是否小于最小值,如果小于我们,把最小值和最小值的位置更新,这样我们就实现了区间的移动,这样不断移动,我们判断移动是否超过N,如果超过N,证明找不到这个点,如果可以,直接break,输出就可以了。

    个人感觉有点莫队的意思。。。

    #include<bits/stdc++.h>
    using namespace std;
    
    int t;
    typedef long long ll;
    const int maxn = 1e6+5;
    
    struct Node
    {
        ll a,b,w;
    } node[maxn<<1];
    
    int n,c;
    ll tree[maxn<<1];
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int x,ll v)
    {
        for(int i=x; i<=n; i+=lowbit(i))
        {
            tree[i] += v;
        }
    }
    
    ll query(int x)
    {
        ll ans = 0;
        for(int i=x; i>0; i-=lowbit(i))
        {
            ans += tree[i];
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&n,&c);
            memset(tree,0,sizeof(tree));
            for(int i=1; i<=n; i++)
                scanf("%lld",&node[i].a);
            ll minn = 0x3f3f3f3f3f;
            int id = 0;
            ll tmp = c;
            for(int i=1; i<=n; i++)
            {     
                scanf("%lld",&node[i].b);
                node[i].w = node[i].a - node[i].b;
                node[i+n].w = node[i].w;
                add(i,node[i].w);
                add(i+n,node[i].w);
                tmp += node[i].w;
                if(tmp < minn)
                {
                    minn = tmp;
                    id = i;
                }
            }
            int cnt = 1;
            int len = id;
            while(minn < 0)
            {
                if(cnt > n)break;
                for(int i=cnt;i<=cnt + len - 1;i++)
                {
                    minn -= node[i].w;
                    if(minn >= 0)
                    {
                        cnt = i+1;
                        break;
                    }
                }
                ll tmp = query(n) - query(cnt-1) + c;
                minn = 0;
                for(int i=n+1;i<=n+cnt-1;i++)
                {
                    tmp += node[i].w;
                    if(tmp < 0)
                    {
                        if(tmp < minn)
                        {
                            minn = tmp;
                            id = i;
                        }
                    }
                }
                len = id - cnt + 1;
            }
            if(cnt > n)printf("-1
    ");
            else printf("%d
    ",cnt);
        }
    }
    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    正则表达式预:
    cookie 二:
    Javascript之运动框架2
    cookie预:
    Javascript之链式运动框架1
    基于Azure的软件部署和开发系列沙龙
    在Docker中安装.NET Core(使用命令行工具)
    Xshell 无法连接虚拟机中的ubuntu的问题
    springboot09-redis
    springboot08-jpa-mysql
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/9691097.html
Copyright © 2011-2022 走看看