ZOJ XXXX Candies(13年长沙网络赛-J题-数学)

题目链接:Click here~~

题意:

有 n 个人,每人手里有若干糖果,有一些人的糖果数量不确定,但给出每相邻三个人的糖果数量和(起始端和末尾端是两个人)。

然后给出若干询问,求出某个人的最大可能的糖果数量。

解题思路:

先将第二个条件中的 sum 相邻项作差,可以得出若干等式 a[3] - a[0] , a[4] - a[1] , a[5] - a[2] , …… , a[n-1] - a[n-4]。

然后在起始端和末尾端可以得到 a[2] 与 a[n-3] 的确定值,可以作为已知使用,再根据上面等式,可以推出所有与已知项下标差为 3的倍数 的项。

其实只要知道一个 a[i] 满足条件 2 % 3 != i % 3,就一定可以得出 a[0] 与 a[1] 里的其中一项,再根据等式 a[0] + a[1] 求出另一项,从而得出整个序列。

如果最后没有将序列确定,那么剩余的一定全部是 2 % 3 != i % 3 的项,且 2 % 3 = n % 3。

由于知道了序列中所有 2 % 3 == i % 3的项,那么可以将原来第二个条件中的 sum 减去已知的这些项,那么我们可以得到一个关于 相邻未知项的和 的等式组。

即 a[0] + a[1] , a[1] + a[3] , a[3] + a[4] ,a[4] + a[6] …… 然后引入两个 fact :

1、相邻项均为负相关,相隔一项均为正相关。

2、一旦某个项的值确定,所有项的值均确定。

于是不妨考虑 a[0] 取值的上界与下界,得出后,即可根据正负相关性,得到所求项的上界。

如何考虑这个上界与下界呢?

将所有的 a[i] 全部转化成 a[i] = (+/-) a[0] + c 的形式,根据 a[i] >= 0 这一唯一约束条件,得出关于 a[0] 的不等式组,求解即可。

#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int N = 1e5 + 5;

int a[N],b[N],sub[N],sum_add[N],sum_sub[N],n;

void go_r(int pos)
{
    if(pos+3 < n)
    {
        a[pos+3] = a[pos] + sub[pos];
        go_r(pos+3);
    }
}

void go_l(int pos)
{
    if(pos-3 >= 0)
    {
        a[pos-3] = a[pos] - sub[pos-3];
        go_l(pos-3);
    }
}

int main()
{
    //freopen("in.ads","r",stdin);
    int m;
    while(~scanf("%d",&n))
    {
        int pos = -1;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i] != -1 && i % 3 != 2)
                pos = i;
        }
        for(int i=0;i<n;i++)
            scanf("%d",&b[i]);
        for(int i=0;i+3<n;i++)
            sub[i] = b[i+2] - b[i+1];
        a[2] = b[1] - b[0];
        go_r(2);
        a[n-3] = b[n-2] - b[n-1];
        go_l(n-3);
        if(pos != -1)
        {
            go_l(pos);
            go_r(pos);
        }
        if(a[1] != -1)
        {
            a[0] = b[0] - a[1];
            go_r(0);
        }
        if(a[0] != -1)
        {
            a[1] = b[0] - a[0];
            go_r(1);
        }
        int a0_min , a0_max;
        if(a[0] == -1)
        {
            a0_min = sum_add[0] = 0;
            for(int i=3;i<n;i+=3)
            {
                sum_add[i] = sum_add[i-3] + sub[i-3];
                a0_min = max(a0_min,-sum_add[i]);
            }

            a0_max = sum_sub[1] = b[0];
            for(int i=4;i<n;i+=3)
            {
                sum_sub[i] = sum_sub[i-3] + sub[i-3];
                a0_max = min(a0_max,sum_sub[i]);
            }
        }
        scanf("%d",&m);
        while(m--)
        {
            int q;
            scanf("%d",&q);
            if(a[q] != -1)
                printf("%d\n",a[q]);
            else
            {
                if(q % 3 == 0)
                    printf("%d\n",a0_max+sum_add[q]);
                else
                    printf("%d\n",-a0_min+sum_sub[q]);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值