zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校(八)

    K Kabaleo Lite(前缀和+高精度(大数处理))

    (1)把一个超过long long范围的数字拆成两个long long存储!

    (2)计算前缀和的操作非常聪明

    代码来自:

    https://blog.nowcoder.net/n/3b2e46a2f0ff4201b1587b1cffb08d6d

    #include<bits/stdc++.h>
    using namespace std;
    const long long N=1e5+9,mod=1e14;                  //控制 m 在1e14范围之内 
    long long a[N],b[N],s[N],n,m,ans;
    int main()
    {
        int T,l,r,i,j,k;
        scanf("%d",&T);
        for(k=1;k<=T;k++)
        {
            memset(a,0,sizeof(a)),memset(b,0,sizeof(b)),memset(s,0,sizeof(s));
            scanf("%lld",&n);
            for(i=0;i<n;i++) scanf("%lld",&a[i]);
            scanf("%lld",&b[0]);
            for(i=1;i<n;i++) scanf("%lld",&b[i]),b[i]=min(b[i],b[i-1]);        //b:个数 
            s[0]=a[0];
            for(i=1;i<n;i++) s[i]=s[i-1]+a[i];                               //s:前缀和  
            l=r=ans=0,m=s[l]*b[l];                                    //以上均从0开始计数 
            while(r<n)                      //遍历
            {
                while(r<n && s[r]<=s[l]) r++;
                if(r==n)break;                            //选取第一个前缀和大于当前的位置 
                m+=b[r]*(s[r]-s[l]),ans+=m/mod,m%=mod;          //m += b[r] * (s[r] - s[l])  加上这一段的数目
                l=r;                                    //更新 l
            }
            printf("Case #%d: %lld ",k,b[0]);
            if(ans) printf("%lld%014lld
    ",ans,m);
            else printf("%lld
    ",m);
        }
    }

    略为暴力的作法:

    (1)用priority队列从大到小储存前缀和

    (2)从前缀和大到小遍历,减去当前的全部个数,下一个前缀和如果没有这么多个数就等于被减完了,跳过,有的话就算上多出来的部分。cnt一直在增加,相当于减掉的越来越多

    (3)用__int128储存大数

    代码来自:

    https://blog.nowcoder.net/n/6cecfd81e1e3465aa75b2b82e29973e9

    #include<bits/stdc++.h>
    #define ll __int128
    #define pii pair<ll,pair<ll,ll> >
    using namespace std;
     
    inline __int128 read(){
        __int128 x=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-')
                f=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*f;
    }
     
    inline void print(__int128 x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>9)
            print(x/10);
        putchar(x%10+'0');
    }
     
    const ll maxn=1e5+10;
    ll a[maxn],b[maxn],c[maxn];
    priority_queue<pii> q;
     
    int main()
    {
     
        ll t;
        t=read();
        ll kk=1;
        while(t--){
            ll n;
            n=read();
            for(ll i=0;i<n;i++) a[i]=read();
            for(ll i=0;i<n;i++) b[i]=read();
            for(ll i=0;i<n;i++){
                if(i) c[i]=c[i-1]+a[i];
                else c[i]=a[i];
            }
            __int128 ans=0;
            ll bb=b[0];
            for(ll i=0;i<n;i++){
                bb=min(bb,b[i]);
                q.push({c[i],{bb,i}});
            }
            ll cnt=0,pos=n;
            while(!q.empty()){
                ll x=q.top().first,y=q.top().second.first,z=q.top().second.second;
                q.pop();
                if(y<=cnt||pos<=z) continue;
                ans+=x*(y-cnt);
                cnt=y;
                pos=z;
            }
            cout<<"Case #";
            print(kk++);
            cout<<": ";
            print(b[0]);
            cout<<" ";
            print(ans);
            cout<<endl;
        }
        return 0;
    }

    最为暴力的作法:

    (1)也是把前缀和数组从大到小排序

    (2)用线段树全部区间修改个数

    这就是我的代码orz

    #include<bits/stdc++.h>
    using namespace std;
    #define ll __int128
    //区间修改
    //点查询
    //线段树记录每个序号的数目
    const int inf=1e9+1e5;
    struct __Sum{
        ll sum;
        int id;
    } Sum[100004];
    ll num[100004<<2],add[100004<<2];
    ll mi=inf;
    int first,vis;
    void push_up(int rt){
        num[rt]=num[rt<<1]+num[rt<<1|1];
    }
    void push_down(int rt,int m){
        if(add[rt]){
            add[rt<<1]+=add[rt];
            add[rt<<1|1]+=add[rt];
            num[rt<<1]+=(m-(m>>1))*add[rt];
            num[rt<<1|1]+=(m>>1)*add[rt];
            add[rt]=0;
        }
    }
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    void build(int l,int r,int rt){
        add[rt]=0;
        if(l==r){
            scanf("%lld",&num[rt]);
            if(vis==0){first=num[rt];vis=1;}
            mi=min(mi,num[rt]);
            num[rt]=mi;
            return;
        }
        int mid=(l+r)>>1;
        build(lson);
        build(rson);
        push_up(rt);
    }
    void update(int a,int b,int c,int l,int r,int rt){
        if(a<=l&&b>=r){
            num[rt]+=(r-l+1)*c;
            add[rt]+=c;
            return;
        }
        push_down(rt,r-l+1);
        int mid=(l+r)>>1;
        if(a<=mid) update(a,b,c,lson);
        if(b>mid) update(a,b,c,rson);
        push_up(rt);
    }
    int query(int a,int b,int l,int r,int rt){
        if(a<=l&&b>=r) return num[rt];
        push_down(rt,r-l+1);
        int mid=(l+r)>>1;
        int ans=0;
        if(a<=mid) ans+=query(a,b,lson);
        if(b>mid) ans+=query(a,b,rson);
        return ans;
    }
    bool cmp(__Sum a,__Sum b){
        return a.sum>b.sum;
    }
    void init(){
        memset(num,0,sizeof(num));
        memset(add,0,sizeof(add));
        memset(Sum,0,sizeof(Sum));
        mi=inf;
        Sum[0].sum=0;
        vis=0;
    }
    inline void print(__int128 x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>9)
            print(x/10);
        putchar(x%10+'0');
    }
    int main(){
        int t;
        scanf("%d",&t);
        for(int c=1;c<=t;++c){
            int n;
            scanf("%d",&n);
            init();
            int tmp;
            for(int i=1;i<=n;++i){
                scanf("%d",&tmp);
                Sum[i].sum=tmp+Sum[i-1].sum;
                Sum[i].id=i;
            }
            build(1,n,1);
            sort(Sum+1,Sum+1+n,cmp);
            int cnt=0;
            __int128 ans=0;
            //num[1]盘,那么计算num[1]次前缀和即可
            for(int i=1;i<=n;++i){
                int tmp=query(Sum[i].id,Sum[i].id,1,n,1);
                if(tmp<=0) continue;
                //当前的数目
                //前面扣除为0之后,后面也要减掉这个值。
                if(cnt+tmp>=first){
                    tmp=first-cnt;
                    ans+=(ll)tmp*Sum[i].sum;
                    break;
                }
                cnt+=tmp;
                ans+=(ll)tmp*Sum[i].sum;
                update(1,n,-tmp,1,n,1);
                //1到n都剪掉当前的数目
            }
            printf("Case #%d: %d ",c,first);
            print(ans);
            printf("
    ");
        }
    }
  • 相关阅读:
    Running ASP.NET Applications in Debian and Ubuntu using XSP and Mono
    .net extjs 封装
    ext direct spring
    install ubuntu tweak on ubuntu lts 10.04,this software is created by zhouding
    redis cookbook
    aptana eclipse plugin install on sts
    ubuntu open folderpath on terminal
    ubuntu install pae for the 32bit system 4g limited issue
    EXT Designer 正式版延长使用脚本
    用 Vagrant 快速建立開發環境
  • 原文地址:https://www.cnblogs.com/rainartist/p/13431834.html
Copyright © 2011-2022 走看看