2013 ACM/ICPC Asia Regional Changsha Online J Candies

AC了,但是不知道为什么,但是恶心的不得了~最近写代码,思路都非常清晰,但是代码各种bug~T.T~
说说思路吧:二分~330ms~  小队友fribbi的思路是离线250msAC~

预处理solve函数(让能求出来的尽量都求出来)-->a[2]a[n-3]已知

①已知a[i]可知a[i+3]
②已知a[i] a[i-1] 或者a[i] a[i+1]或者a[i+1] a[i-1]可知全部

③已知a[0]a[1]a[n-2]a[n-1]可知全部

提问:

①已知则直接输出,不存在a[i+1] a[i-1]已知a[i]未知这种情况,solve已处理

②已知前面或者后面的一个 二分检测(因为至少a[2+2*k],k=0,1,2...已知)

③提问是0位置或者n-1位置 二分检测

检测时候用test数组,因为检测时有赋值,不能对num数组赋值,否则会影响下次的测试~

巨恶心的代码(自己给把自己恶心到了)~

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cmath>
  4 #include <algorithm>
  5 using namespace std;
  6 #define N 100000
  7 #define back num[i]=sum[i-1]-num[i-1]-num[i-2]
  8 #define front num[i]=sum[i+1]-num[i+1]-num[i+2]
  9 int num[N+10];
 10 int sum[N+10];
 11 int test[N+10];
 12 int n;
 13 int cal(int id){//make sure id>=2&&id<n-2
 14 //return 1 O(N)全部求出来了,return 0,代表只求出了一部分的数字
 15     int i,least;
 16     if(num[id-1]!=-1){//左边已知
 17         for(i=id-2;i>=0;i--) front;for(i=id+1;i<n;i++) back;return 1;
 18     }
 19     else if(num[id+1]!=-1){//右边已知
 20         for(i=id-1;i>=0;i--) front;for(i=id+2;i<n;i++) back;return 1;
 21     }
 22     else{//左右都未知
 23         least=sum[id+1]-num[id];
 24         for(i=id+3;i<n&&num[i]==-1;i+=3){
 25             num[i]=sum[i-1]-least;if(i+1<n) least=sum[i+1]-num[i];
 26         }
 27         least=sum[id-1]-num[id];
 28         for(i=id-3;i>0&&num[i]==-1;i-=3){
 29             num[i]=sum[i+1]-least;if(i-1>=0) least=sum[i-1]-num[i];
 30         }
 31         return 0;
 32     }
 33 }
 34 void solve(){
 35     int i,j;
 36     if(num[0]!=-1){num[1]=sum[0]-num[0];for(i=2;i<n;i++) back;}
 37     else if(num[1]!=-1){num[0]=sum[0]-num[1];for(i=2;i<n;i++)back;}
 38     else if(num[n-1]!=-1){num[n-2]=sum[n-1]-num[n-1];for(i=n-3;i>=0;i--)front;}
 39     else if(num[n-2]!=-1){num[n-1]=sum[n-1]-num[n-2];for(i=n-3;i>=0;i--)front;}
 40     else for(j=0,i=2;i<n-2&&!j;i++) if(num[i]!=-1) j=cal(i);
 41     //j相当于flag,flag=1代表已经全部求出,不需要继续循环了
 42     return ;
 43 }
 44 int backword(int i,int id){
 45     for(;i<n;i++){
 46         if(test[i]==-1) test[i]=sum[i-1]-test[i-1]-test[i-2];
 47         if(test[i]<0) if(test[i]<0) return (i%3==id%3)?1:2;
 48     }
 49     return 0;//合法
 50 }
 51 int forward(int i,int id){
 52     for(;i>=0;i--){
 53         if(test[i]==-1) test[i]=sum[i+1]-test[i+1]-test[i+2];
 54         if(test[i]<0) return (i%3==id%3)?1:2;
 55     }
 56     return 0;//合法
 57 }
 58 bool check(int id,int key,int type){
 59     int i,j;
 60     for(i=0;i<n;i++) test[i]=num[i];test[id]=key;
 61     //test[i-1]已知 test[i]测试 向两边检查
 62     if(type==0){
 63         if(backword(id+1,id)==2||forward(id-2,id)==2) return 0;
 64     }
 65     //test[i+1]已知 test[i]测试 向两边检查
 66     else if(type==1){
 67         if(backword(id+2,id)==2||forward(id-1,id)==2) return 0;
 68     }
 69     //test[0]测试,test[1]未知,test[2]已知 向后检查
 70     else if(type==2){
 71         test[1]=sum[1]-test[0]-test[2];
 72         if(backword(3,id)==2) return 0;
 73     }
 74     //test[n-1]测试,test[n-2]未知,test[n-3]已知 向前检查
 75     else {
 76         test[n-2]=sum[n-2]-test[n-1]-test[n-3];
 77         if(forward(n-3,id)==2) return 0;
 78     }
 79     return 1;
 80 }
 81 int bin(int type,int id){//二分检查最大值,能大则大
 82     int left=0,right=sum[id],mid,ans=left;
 83     while(left<=right){
 84         mid=(left+right)/2;
 85         if(check(id,mid,type))//正好 太小
 86             {left=mid+1;ans=mid;}
 87         else right=mid-1;//太大
 88     }
 89     return ans;
 90 }
 91 int main(){
 92     int i,j;
 93     int p,q;
 94     int res;
 95     while(scanf("%d",&n)!=EOF){
 96         for(i=0;i<n;i++) scanf("%d",&num[i]);
 97         for(i=0;i<n;i++) scanf("%d",&sum[i]);
 98 
 99         num[2]=sum[1]-sum[0];//导火索
100         num[n-3]=sum[n-2]-sum[n-1];//导火索
101 
102         solve();//把所有的可以计算出来的全部计算出来
103 
104         scanf("%d",&q);
105         while(q--){
106             scanf("%d",&p);
107             if(num[p]!=-1) res=num[p];//num[i]已知
108             else if(p-1>=0&&num[p-1]!=-1) res=bin(0,p);//num[i-1]已知
109             else if(p+1<n&&num[p+1]!=-1)  res=bin(1,p);//num[i+1]已知
110             else if(p==0)   res=bin(2,p);//num[0]未知,num[1]未知,num[2]已知
111             else if(p==n-1) res=bin(3,p);//num[n-1]未知,num[n-2]未知,num[n-3]已知
112             printf("%d
",res);
113         }
114     }
115     return 0;
116 }
View Code
原文地址:https://www.cnblogs.com/-sunshine/p/3337393.html