ACM-ICPC 2018 南京赛区网络赛 G题 Lpl and Energy-saving Lamps

版权声明:本文为博主原创文章,转载请联系博主(通常都会同意就是了) https://blog.csdn.net/cccccwb/article/details/82289909

       题目大意:有n个房间,第i个房间内有ki盏白炽灯。现在准备将这些白炽灯全部换成节能灯。管家每个月购买m盏节能灯,之后会按照房间列表一间一间地查看是否需要更换。当管家遇见一个尚未更换节能灯的房间,并且他手上有足够多的节能灯时,他会将房间内的所有白炽灯全部替换为节能灯。不管他路过这个房间后是否换了灯,他都会继续前往下一个房间。如果他走过所有房间之后手中仍有多余的节能灯,他将会把这些节能灯留到下个月继续使用。你的任务是对于给出的询问d,求出d个月后有多少房间已经换好了节能灯,以及管家手上有多少盏节能灯。

      输入:第一行有两个数字,分别是n(1<=n<=100000)和m(1<=m<=100);第二行有n个数字,第i个数字ki(1<=ki<=10000)表示第i个房间有多少盏白炽灯;第三行有一个数字q(1<=q<=100000),表示一共有q组询问;第四行有q个数字,第i个数字di(1<=di<=100000)表示第i组询问所询问的月份。

      输出:一共q行,每行两个数字,分别表示当月有多少房间已经换好灯以及管家手上仍有多少灯。

      题解:

      一道比较简单的利用线段树维护的模拟题。

      首先考虑暴力模拟,记录下管家当前手中有多少白炽灯,然后一个月一个月地跑,用数组记录下每个月的答案(因为di<=100000所以开得下数组)。但是这个写法效率上无法承受——极端情况下效率可以达到O(nd),也就是10的10次方。注意到每个房间只会被换一次灯,每轮模拟跑全部房间没有必要。于是考虑采用线段树维护,线段树中记录下房间灯数的最小值。每一轮模拟的时候,找出管家当前位置到结尾为止的房间中,最近的一个可以换灯的房间。具体操作为,在线段树中查询时,如果左子树的最小值小于等于当前灯数,就到左子树中继续寻找,否则考虑右子树。找到之后,更新答案,并将这个节点的值设为INF,在回溯的时候更新线段树。如果所有节点的最小值都比当前灯数要大,则说明这一轮模拟结束,进入下一轮。这样的话,一共只跑了总月份数加上总房间数再乘以log2(n),可以通过。

      (考场上看错题,以为是暴力模拟,WA了两发之后心态炸了,脑出解法之后扔给同学码了……因此底下的代码不是我写的。)

      代码:

//code by redwind
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iomanip>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#define debug(x) cerr<<#x<<"="<<x<<endl
#define INF 0x7f7f7f7f
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
inline int init()
{
    int now=0,ju=1;char c;bool flag=false;
    while(1)
    {
        c=getchar();
        if(c=='-')ju=-1;
        else if(c>='0'&&c<='9')
        {
            now=now*10+c-'0';
            flag=true;
        }
        else if(flag)return now*ju;
    }
}
inline long long llinit()
{
    long long now=0,ju=1;char c;bool flag=false;
    while(1)
    {
        c=getchar();
        if(c=='-')ju=-1;
        else if(c>='0'&&c<='9')
        {
            now=now*10+c-'0';
            flag=true;
        }
        else if(flag)return now*ju;
    }
}
#define lson (now<<1)
#define rson (now<<1|1)
#define mid ((l+r)>>1)
class node
{
	public:
		int minx;
}tree[2000005];
int a[2000005],n,m;
int ans1[2000005],ans2[2000005];
int cnt=0;
inline void update(int now)
{
	tree[now].minx=min(tree[lson].minx,tree[rson].minx);
}
inline void Build_Tree(int l,int r,int now)
{
	if(l==r)
	{
		tree[now].minx=a[l];
		return;
	}
	else
	{
		Build_Tree(l,mid,lson);
		Build_Tree(mid+1,r,rson);
		update(now);
	}
}
inline void Modify_Tree(int l,int r,int pos,int now)
{
	if(l==r)
	{
		tree[now].minx=INF;
		return;
	}
	else
	{
		if(pos<=mid)Modify_Tree(l,mid,pos,lson);
		else if(pos>mid)Modify_Tree(mid+1,r,pos,rson);
		update(now);
	}
}
inline int Query_Tree(int l,int r,int now,int x)
{
	if(l==r)
	{
		return l;
	}
	else
	{
		if(tree[lson].minx<=x)
		{
			return Query_Tree(l,mid,lson,x);
		}
		else if(tree[rson].minx<=x)
		{
			return Query_Tree(mid+1,r,rson,x);
		}
		else return -1;
	}
}
int main()
{
	n=init();m=init();
	int tmp=0,c=0,pos;
	for(int i=1;i<=n;i++)
	{
		a[i]=init();
	}
	Build_Tree(1,n,1);
	while(cnt!=n&&c!=100000)
	{
		c++;tmp+=m;
		while(pos=Query_Tree(1,n,1,tmp),pos!=-1)
		{
			tmp-=a[pos];
			Modify_Tree(1,n,pos,1);
			cnt++;
		}
		ans1[c]=cnt;ans2[c]=tmp;
	}
	int t,q;q=init();
	for(int i=1;i<=q;i++)
	{
		t=init();if(t>c)t=c;
		printf("%d %d\n",ans1[t],ans2[t]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/cccccwb/article/details/82289909