ZOJ Candies 长沙


题意:有n个小孩,他们手上有很多糖果,善良的小孩会告诉你他有多少糖果,相反,则不会告诉你,但是会告诉你他和他的邻居的糖果和,求出每个人最多拥有多少糖果。


题目链接:http://acm.zju.edu.cn/changsha/showProblem.do?problemId=31


思路:n个人的号码是有1-n,,由于每次给出的是三个数的和(最边上的可以认为是0),很容易确定3,6,9,12,,,,,,的糖果数量,

另外,在以下几种情况下,这个序列的值都可以确定:

            1.如果在剩余的那些号码中有已知的量,那么这个序列的值都可以确定;

            2.如果n%3==0 || n%3==1 这个序列分别从头到尾和从尾到开始在求一次就可以确定;

那么接下来的情况(n%3==2)就是不确定这个序列,(除了Mode3==0的位置确定外)

对于以下序列 a,b,c,d,e,f,g,h,,,,,,

sum1=a+b;           sum2=a+b+c;          sum3=b+c+d;       sum4=c+d+e;

sum5=d+e+f;        sum6=e+f+g;           sum7=f+g+h;       sum8=g+h;

由于确定c,f,的值,那么上述不等式可以转换为:

x1 = a + b;   x2 = b + d;  x3 = d + e;  x4 = e + g; x5 = g + h;  (x1,x2,x3,x4,x5都可以求出来)

那么上述的这些式子就全部可以转换为和a有关系的函数式: b = x1 - a ; d = x2 - b = x2 - x1 + a; ,,,,,,,,,,,,

每个变量本身是大于等于0,所以我们可以确定a的最大值和最小值,

从而每个变量的最大值也就确定~~~~~~~


比赛的时候没写出来,代码太渣,,,还是纪念下来,

 

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define maxn 100010
#define inf 0x3f3f3f3f

int s[maxn]; //记录两个未知数的和
int num[maxn];
int num2[maxn];
int sum[maxn];

int main()
{
    int n,m,query,pos;
    while(~scanf("%d",&n)){
        memset(s,0,sizeof(s));
        memset(num,0,sizeof(num));
        memset(num2,0,sizeof(num2));
        memset(sum,0,sizeof(sum));
        bool flag=false;
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
            if(i%3){if(num[i]!=-1) {flag=true;pos=i;}} //记录是否有除了3,6,9..之外的值给出。。。
            num2[i]=num[i];
        }

        for(int i=1;i<=n;i++)
            scanf("%d",&sum[i]);

        for(int i=1;i<=n;i++) //确定位置3.6.9.12....的值
            if(i%3==0) num[i] = sum[i-1] - sum[i-2] + num[i-3];

        if(n%3==0){        //确定n%3==0序列
            for(int i=n;i>=1;i--)   //确定mode3==1的位置的数
                if(i%3==1)
                num[i] = sum[i+1] - sum[i+2] + num[i+3];

            for(int i=1;i<=n;i++)
                if(i%3==2) //确定mode3==2的位置的数
                num[i] = sum[i] -num[i-1] -num[i+1];


            scanf("%d",&m);
            while(m--){
                scanf("%d",&query); query++;
                printf("%d\n",num[query]);
            }
        }
        else if(n%3==1){   //确定n%3==1序列
            num[n] = sum[n] - num[n-1];
            for(int i=n-2;i>=1;i--)
                num[i] = sum[i+1] - num[i+1] -num[i+2];

            scanf("%d",&m);
            while(m--){
                scanf("%d",&query); query++;
                printf("%d\n",num[query]);
            }
        }
        else{
            if(flag==true){ //有值给出的情况
                if(pos%3==2){
                    num[pos-1] = sum[pos-1] -num[pos-2] -num[pos];
                    pos=pos-1;
                }
                for(int i=pos-2;i>=1;i--)
                    num[i]=sum[i+1]-num[i+1] -num[i+2];
                for(int i=pos+1;i<=n;i++)
                    num[i]=sum[i-1]-num[i-1]-num[i-2];

                scanf("%d",&m);
                while(m--){
                    scanf("%d",&query);query++;
                    printf("%d\n",num[query]);
                }
            }
            else{
                 int t=1; //记录两个变量的和
                 for(int i=1;i<=(n-2);i++){
                    if(i%3==2){
                        s[t++] = sum[i] - num[i+1];
                        s[t++] = sum[i+1] - num[i+1];
                    }
                 }
                 s[t] = sum[n];

                 int mi=0,ma=inf,temp=0,cnt=1; //记录a 的可变范围
                 for(int i=2;i<=n;i++){
                    if(i%3){
                        num[i] = s[cnt++] - temp;
                        if(i%3==1) mi=max(mi,-num[i]);
                        else if(i%3==2) ma=min(ma,num[i]);
                        temp=num[i];
                    }
                 }
                num[1] = 0;
                scanf("%d",&m);
                while(m--){
                    scanf("%d",&query);
                    query++;
                    if(num2[query]!=-1) printf("%d\n",num2[query]);
                    else{
                        if(query%3==0) printf("%d\n",num[query]);
                        else if(query%3==1) printf("%d\n",num[query]+ma);
                        else printf("%d\n",num[query]-mi);
                    }
                }
            }
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值