• 【ATcoder s8pc_3 F】 寿司


    http://s8pc-3.contest.atcoder.jp/tasks/s8pc_3_f (题目链接)

    题意

      有一个长度为$N$的数列$A$,初始为$0$。$Q$次操作,每次两个参数$x,y$。

    1. 在$A[1]...A[x]$中找出最小的数,如果有多个找编号最小的,假设为$u$。
    2. $A[u]++$。
    3. 重复这个过程$y$次。

      输出最后的$A$序列。

    Solution

      可以发现,数列$A$肯定是单调不降的,那就非常好做了。

      用一个线段树维护数列,区间赋值,支持区间求和。在询问区间中二分找到一个位置$pos$,$pos$到$x$的数改成与$pos-1$大小相同所需要花费的次数不超过$y$。剩余的次数全部加上就好。

    细节

      注意特判$x=1$和$A[x-1]-A[x]>=y$的情况。

    代码

    // ATcoder 
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf (1ll<<30)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
    using namespace std;
    
    const int maxn=100010;
    int n,Q;
    struct node {int l,r;LL s,tag;}tr[maxn<<2];
    
    void pushdown(int k) {
    	int l=k<<1,r=k<<1|1;LL w=tr[k].tag;tr[k].tag=0;
    	tr[l].s=(tr[l].r-tr[l].l+1)*w;tr[l].tag=w;
    	tr[r].s=(tr[r].r-tr[r].l+1)*w;tr[r].tag=w;
    }
    void modify(int k,int s,int t,LL val) {
    	int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    	if (l==s && r==t) {tr[k].s=val*(tr[k].r-tr[k].l+1);tr[k].tag=val;return;}
    	if (tr[k].tag) pushdown(k);
    	if (t<=mid) modify(k<<1,s,t,val);
    	else if (s>mid) modify(k<<1|1,s,t,val);
    	else modify(k<<1,s,mid,val),modify(k<<1|1,mid+1,t,val);
    	tr[k].s=tr[k<<1].s+tr[k<<1|1].s;
    }
    void build(int k,int s,int t) {
    	tr[k].l=s;tr[k].r=t;
    	if (s==t) return;
    	int mid=(s+t)>>1;
    	build(k<<1,s,mid);
    	build(k<<1|1,mid+1,t);
    }
    LL query(int k,int s,int t) {
    	int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    	if (l==s && r==t) return tr[k].s;
    	if (tr[k].tag) pushdown(k);
    	if (t<=mid) return query(k<<1,s,t);
    	else if (s>mid) return query(k<<1|1,s,t);
    	else return query(k<<1,s,mid)+query(k<<1|1,mid+1,t);
    }
    
    int main() {
    	scanf("%d%d",&n,&Q);
    	build(1,1,n);
    	for (int x,i=1;i<=Q;i++) {
    		LL y;
    		scanf("%d%lld",&x,&y);
    		if (x==1) {modify(1,1,1,query(1,1,1)+y);continue;}
    		if (query(1,x-1,x-1)-query(1,x,x)>=y) {modify(1,x,x,query(1,x,x)+y);continue;}
    		int l=2,r=x,pos;
    		while (l<=r) {
    			int mid=(l+r)>>1;
    			if (query(1,mid-1,mid-1)*(x-mid+1)-query(1,mid,x)<=y) r=mid-1,pos=mid;
    			else l=mid+1;
    		}
    		LL val=query(1,pos-1,pos-1),num=x-pos+1;
    		y-=val*num-query(1,pos,x);
    		modify(1,pos,x,val);++num;
    		if (y/num) modify(1,pos-1,x,val+y/num);
    		if (y%num) modify(1,pos-1,pos-2+y%num,val+y/num+1);
    	}
    	for (int i=1;i<=n;i++) printf("%lld
    ",query(1,i,i));
    	return 0;
    }
    
  • 相关阅读:
    微信小程序学习Course 9-2 云存储功能
    微信小程序学习Course 9-1 云数据库功能
    微信小程序学习Course 9 云开发功能
    微信小程序学习Course 6 界面交互API函数
    微信小程序学习Course 3-3 JS时间类型学习
    微信小程序案例TODO备忘录
    微信小程序学习Course 3-2 JS数组对象学习
    微信小程序学习Course 8 本地缓存API
    微信小程序学习Course 7 定时器功能
    常用excel函数语法及说明
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6613856.html
Copyright © 2020-2023  润新知