2013 ACM/ICPC 长沙网络赛-Candies

这个题大意是说n个学生站成一行,其中他们会告诉你他们手中的糖果(如果为-1则为他不愿意告诉你),然后后面会给你相邻3个人(如果存在,头尾是2个)的糖果之和,接下来有m次询问,每次询问让你输出地k个人最多有多少个糖果。

唉,昨天比赛无限悲剧。

通过题意我们可以知道,至少为3的倍数的人我们是可以求他手中有多少颗糖的,首先来考虑可以求出所有人的糖果的情况。

1、不难发现,当人数为3的倍数,或3的倍数+1,这样的情况是不需要告诉任何人手中的糖果可以直接确定每个人手中有多少颗糖果的。

a、当为3的倍数的时候,我们首先可以求出3的倍数位置的所有人的糖果数,然后会发现倒数第二个也是可以知道的,也就是说最后3个人我们已经知道了2个人手中的糖果,所以反推回来就可以求出所有人手中的糖果。

b、当为3的倍数+1的时候,同样的,3的倍数位置的人手中的糖果数量我们是可以准确推出的,那么我们就可以得到倒数第二个人的糖果数,而倒数第一个人的糖果数也自然而然知道了,也就是也知道了相邻2个人的糖果数,所以可以倒推求出所有人的糖果数

c、当我们用上述方法推出所有能推出的人的糖果数后,若发现其中任一一个相邻3个人中有2个是已知,那么所有的人的糖果数我们都可顺利求出。

对于这种情况直接输出推出后的答案即可

2、当我们无法推出所有的人的糖果,也就是说每3个人中我们有2个人不知道,此时人数一定为3*n+2。

其实画图我们可以发现,由于每3个人我们可以确定一个,那么第一个人若增加,那么第二个必将减少,又由于第三个人已知,所以第四个人也将增加......不难发现,每相邻3个人他们的是相关的(3的倍数除外),也就是说当第一个人能取得最大值的时候第4个,第7个......都能取得最大值。同样的,当第1个取得最小值,则第二个是最大值,第5个,第8个.......也是最大值,所以直接从小到大枚举第一个人手中的糖果值(对于这种情况,第一个人必然不知道,因为如果知道,则所有人都可以推出),往后推,若能成功推出,这此时第2个,第5个,第8个.....都为最大值,同样的,对第一个人从大到小枚举糖果值,若能成功推出,则此时第1个人,第4个人,第7个人.......都为最大值。
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=100100;
int n,m,a[maxn],b[maxn],s[maxn],ans[maxn];
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
	memset(s,0,sizeof(s));
	a[0]=a[n+1]=0;
	b[0]=b[n+1]=0;
	for(int i=1;i<=n;i++)
	    scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	    scanf("%d",&s[i]);
	for(int i=0;i+3<=n;i++)
	    if(a[i]!=-1)
		a[i+3]=s[i+2]-s[i+1]+a[i];
	for(int i=n+1;i-3>0;i--)
	    if(a[i]!=-1)
		a[i-3]=s[i-2]-s[i-1]+a[i];
	bool is=0;
	int st;
	for(int i=1;i+2<=n;i++)
	    if((a[i]!=-1&&a[i+1]!=-1)||(a[i]!=-1&&a[i+2]!=-1)||(a[i+1]!=-1&&a[i+2]!=-1))
	    {
		is=1;
		st=i;
		break;
	    }
	if(is)
	{
	    int pos;
	    if(a[st]!=-1&&a[st+1]!=-1)
		pos=st+2;
	    if(a[st]!=-1&&a[st+2]!=-1)
	    {
		a[st+1]=s[st+1]-a[st]-a[st+2];
		pos=st+3;
	    }
	    if(a[st+1]!=-1&&a[st+2]!=-1)
		pos=st+3;
	    for(int i=pos;i<=n;i++)
		if(a[i]==-1)
		    a[i]=s[i-1]-a[i-1]-a[i-2];
	    for(int i=pos-1;i>=1;i--)
		if(a[i]==-1)
		    a[i]=s[i+1]-a[i+1]-a[i+2];
	    scanf("%d",&m);
	    while(m--)
	    {
		int val;
		scanf("%d",&val);
		val++;
		printf("%d\n",a[val]);
	    }
	}
	else
	{
	    for(int i=1;i<=n;i++)
	    {
		ans[i]=a[i];
		b[i]=a[i];
	    }
	    for(int i=0;i<=s[2]-a[3];i++)
	    {
		bool is=0;
		a[1]=i;
		for(int j=2;j<=n;j++)
		{
		    if(j%3==0)
		    {
			if(s[j-1]!=a[j-2]+a[j-1]+a[j])
			{
			    is=1;
			    break;
			}
			continue;
		    }
		    if(b[j]==-1)
		    {
			a[j]=s[j-1]-a[j-1]-a[j-2];
			if(a[j]<0)
			{
			    is=1;
			    break;
			}
		    }

		}
		if(!is&&a[n]+a[n-1]==s[n])
		    break;
	    }
	    for(int i=2;i<=n;i+=3)
		if(ans[i]==-1)
		    ans[i]=a[i];
	    for(int i=s[2]-a[3];i>=0;i--)
	    {
		bool is=0;
		a[1]=i;
		for(int j=2;j<=n;j++)
		{
		    if(j%3==0)
		    {
			if(s[j-1]!=a[j-2]+a[j-1]+a[j])
			{
			    is=1;
			    break;
			}
			continue;
		    }
		    if(b[j]==-1)
		    {
			a[j]=s[j-1]-a[j-1]-a[j-2];
			if(a[j]<0)
			{
			    is=1;
			    break;
			}
		    }
		}
		if(!is&&a[n]+a[n-1]==s[n])
		    break;  
	    }
	    for(int i=1;i<=n;i+=3)
		if(ans[i]==-1)
		    ans[i]=a[i];
	    scanf("%d",&m);
	    while(m--)
	    {
		int val;
		scanf("%d",&val);
		val++;
		printf("%d\n",ans[val]);
	    }
	}
    }
    return 0;
}



你可能感兴趣的:(模拟)