数学+模拟-2013 ACM/ICPC Asia Regional Changsha Online J 题

 题目链接:

http://acm.zju.edu.cn/changsha/showProblem.do?problemCode=J

题目意思:

有n个人,每个人有一个数(>=0)。给出n个数,-1表示该人所持有的数未知,否则为该人所持有的数。

给出n个数p[n],p[i]表示当前人为中心的三个连续的数的和。有m种查询t,查询第t个人能够持有的最大数。

解题思路:

数学+模拟。

假设n个数分别为a1,a2,a3....an ,将开始和最后一个数记为0,a[0]=a[n+1]=0;

则有

a0+a1+a2=p0

a1+a2+a3=p1

a2+a3+a4=p2

.....

an-1+an+an+1=pn-1

显然p1-p2=a3,a6-a3=p4-p3...所以可以推得a[i%3==0])。同理从后往前可以推得a(n-2)=p(n-2)-p(n-1)  如果(n-2)%3不为零或者某一个a[i]!=-1(i%3不为0),则可以全部推出——从该位置从前往后和从后往前各一次。

否则的话,至于%3==1和%3==2的都没有推出来,但是ai-a(i+3)=pi-p(i+1)为定值,a1,a4,a7....增减性相同,同为最大,同为最小。有a1+a2为定值,所以%3==1和%3==2的增减性相反。

分别求出两种余数的最大值。

对于i%3==1的情况,可以假设a[1]它为最大值p[0],则a[i%3==1]均为最大值,但,要保证a[i%3==2]>=0,所以就统计a[i%3==2]的最小值tmp,如果tmp<0,则它增加到0,所有的a[i%3==1]减去abs(tmp).

同理可以求出 a[i%3==2]的最大值。

PS:尽最大可能找出题目的特点,性质。

求相关的最小值贪心有问题,见代码后面样例。

代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 110000
int a[Maxn],p[Maxn];
int Ma[Maxn];
int tt[Maxn];

int main()
{
   int n;

   // printf("%d\n",INF);
   while(~scanf("%d",&n))
   {
       bool flag=false;
       int re;
       for(int i=1;i<=n;i++)
       {
           scanf("%d",&a[i]);
           if(a[i]==-1) //不确定
                continue;
           if(i%3&&i%3!=(n-2)%3) //有其他的,可以全部推出
           {
               flag=true;
               re=i;
           }
       }
       a[0]=a[n+1]=0;
       if((n-2)%3) //不为零,可以全部推出
       {
           flag=true;
           re=n-2;
       }
       for(int i=0;i<n;i++)
            scanf("%d",&p[i]);
       for(int i=3;i<=n;i+=3) //求出a[i%3==0]
            a[i]=p[i-2]-p[i-3]+a[i-3];
       if((n-2)%3) //从后往前,依次求出
       {
           for(int i=n-2;i>=1;i-=3)
                a[i]=p[i]-p[i+1]+a[i+3];
       }
       if(flag) //可以全部推出来
       {
           for(int i=re;i<n;i++) //>=re的都知道了,
           {
               if(i%3==1)
                 a[i+1]=p[i]-a[i]-a[i+2];
               else if(i%3==2)
                    a[i+2]=p[i]-a[i+1]-a[i];
                else
                    a[i+2]=p[i]-a[i]-a[i+1];
           }
           for(int i=re;i>=1;i--) //求<=re的 后面已经已知了
               a[i-1]=p[i-1]-a[i]-a[i+1];
       }
       if(!flag)
       {
           memcpy(tt,a,sizeof(a));
           Ma[1]=p[0]; //置为最大
           tt[1]=p[0];
           int res=0;
           for(int i=2;i<=n;i++)
           {
               if(i%3==0)
                    continue;
               int tmp=p[i-2]-tt[i-2]-tt[i-1];
               tt[i]=tmp;
               if(i%3==1)
                   Ma[i]=tmp;
               else if(tmp<res) //统计%3==2的最小值
                     res=tmp; //
           }
           if(res<0) //保证a[i%3==2]>=0
           {
               for(int i=1;i<=n;i+=3)
                    Ma[i]+=res;
           }
           Ma[2]=p[0];
           memcpy(tt,a,sizeof(a));
           tt[2]=p[0];
           tt[1]=0;
           res=0;
           for(int i=4;i<=n;i++)
           {
               if(i%3==0)
                    continue;
                tt[i]=p[i-2]-tt[i-1]-tt[i-2];
                if(i%3==2)
                    Ma[i]=tt[i];
                else if(tt[i]<res)
                        res=tt[i];

           }
           if(res<0)
           {
               for(int i=2;i<=n;i+=3)
                    Ma[i]+=res;
           }

       }
       int m;

       scanf("%d",&m);
       while(m--)
       {
           int tmp;
           scanf("%d",&tmp);
           tmp++;
           if(flag) //已经全部推出了
                printf("%d\n",a[tmp]);
           else
           {
               if(tmp%3==0) //可以推出来的
                   printf("%d\n",a[tmp]);
               else
                    printf("%d\n",Ma[tmp]); //能够取得的最大值
           }
       }


   }
   return 0;
}
/*
5
1 -1 -1 -1 -1
2 3 4 3 2
5
0 1 2 3 4
*/
/*
比如
a1+a2=3
a2+a3=4
a3+a4=5
a4+a5=3
的话,a2按照求相关的两个方程最小的话为3 但是推得a5=-1
其实 a2可以为2的。
*/


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值