2013Changsha Online J题

【题意】

有N个数,非负。其值Ai如果不确定则为-1,否则给定一非负数。另外给定N个数,非负,第i个数Si为与第i个数相邻的左右两个和它自身的值的和。即S1 = A1 + A2, S2 = A1 + A2 + A3....

询问M次,每次询问第i个数Ai可以取得的最大值。

【分析】

从前往后,对于第i%3 == 0的数的值是可以确定的。比如A3 = S2 - S1。

从后往前,对于第(n-i+1)%3 == 0的数的值也是可以确定的。同理

这样当n%3 == 0和n%3 == 1的数列是可以确定的了。

当n % 3 ==2时,只能从前往后确定i%3==0的数。考察

A1 + A2 = S2 - A3 = B1

A2 + A4 = S3 - A3 = B2

A4 + A5 = S5 - A6 = B3

A5 + A7 = S6 - A6 = B4

.....

以上方程组的秩为未知数个数 - 1,可得自由变量个数为1,那么确定其中一个变量取值范围即可。(膜拜队友^.^)

考察A1的取值范围,

A2 = B1 - A1 = K1 - A1

A4 = B2 - A2 = B2 - B1 + A1 = K2 + A1

A5 = B3 - A4 = B3 - B2 + B1 - A1 = K3 - A1

A7 = B4 - A5 = B4 - B3 + B2 - B1+ A1 = K4 + A1

.....

需要保证所有数非负,那么A1取得最大值为min{K1,K3,K5,.....},min{}数据保证为非负

同理,A1 取得最小值应该为所有min{K2,K4,K6,....},如果min{}值为非负,那么A1取0,如果该值为负,A1取其绝对值。

这样就能确定A1的最大、最小值。

当A1取最大值时,相应A4、A7、。。。也取得最大值。

当A1取最小值时,A2取得最大值,那么A5.。。。也取得最大值。

问题可解。

O(N)求出B1、K1....

总复杂度O(N)

【Mark】

比赛的时候写了个暴力来对拍。。。可惜比赛的时候把A1的最小值确定错了。。。跪!

代码写了近400行,膜拜100行内的大神!

 

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<math.h>
  4 #include<algorithm>
  5 
  6 using namespace std;
  7 
  8 #define LL long long
  9 #define inf 100000000
 10 const int maxn = 100010;
 11 
 12 int n ,m;
 13 LL a[maxn];//给定的A数组
 14 LL seq[maxn];//给定的
 15 
 16 LL sum[maxn];//从前往后求和
 17 LL sss[maxn];//从后往前求和
 18 LL b[maxn];//能确定的数的值,不能确定为-1
 19 LL c[maxn];//求出A1、A4。。。。等i%3==1的数的最大值
 20 LL d[maxn];//求出A2、A5。。。。等i%3==2的数的最大值
 21 LL bb[maxn]; //题解中的B数组
 22 LL ff[maxn];//题解中的K数组
 23 
 24 /***********以下为暴力对拍******************/
 25 bool check(int pos,LL val)
 26 {
 27     for (int i=1; i<=n; i++)
 28     {
 29         c[i] = b[i];
 30     }
 31     c[pos] = val;
 32     if (pos % 3==1)
 33     {
 34         if (pos == 1)
 35         {
 36             c[pos+1] = seq[pos+1] - c[pos] - c[pos+2];
 37         }
 38         else
 39         {
 40             c[pos+1] = seq[pos] - c[pos] - c[pos-1];
 41         }
 42         if (c[pos+1]<0)
 43             return false;
 44         for (int i=pos+2; i<=n; i++)
 45         {
 46             c[i] = seq[i-1] - c[i-1] - c[i-2];
 47             if (i % 3 == 0)
 48             {
 49                 if (b[i] != c[i])
 50                     return false;
 51             }
 52             if (c[i] < 0)
 53                 return false;
 54         }
 55         for (int i=pos-1; i>=1; i--)
 56         {
 57             c[i] = seq[i+1] - c[i+1] - c[i+2];
 58             if (i % 3 == 0)
 59             {
 60                 if (b[i] != c[i])
 61                     return false;
 62             }
 63             if (c[i] < 0)
 64                 return false;
 65         }
 66     }
 67     else if (pos % 3 == 2)
 68     {
 69         if (pos == n)
 70         {
 71             c[pos-1] = seq[pos-1] - c[pos] - c[pos-2];
 72         }
 73         else
 74         {
 75             c[pos-1] = seq[pos] - c[pos] - c[pos+1];
 76         }
 77         if (c[pos-1]<0)
 78             return false;
 79         for (int i=pos+1; i<=n; i++)
 80         {
 81             c[i] = seq[i-1] - c[i-1] - c[i-2];
 82             if (i % 3 == 0)
 83             {
 84                 if (b[i] != c[i])
 85                     return false;
 86             }
 87             if (c[i] < 0)
 88                 return false;
 89         }
 90         for (int i=pos-2; i>=1; i--)
 91         {
 92             c[i] = seq[i+1] - c[i+1] - c[i+2];
 93             if (i % 3 == 0)
 94             {
 95                 if (b[i] != c[i])
 96                     return false;
 97             }
 98             if (c[i] < 0)
 99                 return false;
100         }
101     }
102     else
103     {
104         return true;
105     }
106     return true;
107 }
108 
109 LL solve(int pos)
110 {
111     if (pos % 3 == 1)
112     {
113         LL res = inf;
114         if (pos == 1)
115         {
116             res = min(res, seq[2] - b[3]);
117             res = min(res,seq[1]);
118         }
119         else
120         {
121             res = min(res, seq[pos] - b[pos-1]);
122             res = min(res, seq[pos-1] - b[pos-1]);
123             if (pos + 1 < n)
124                 res = min(res ,seq[pos+1] - b[pos + 2]);
125             else
126                 res = min(res,seq[n]);
127         }
128         //    printf("resw = %lld\n",res);
129         while (res>0)
130         {
131             if (check(pos, res))
132                 break;
133             res--;
134         }
135         return res;
136     }
137     else if (pos % 3 ==2)
138     {
139         LL res = inf;
140         if (pos == 2)
141         {
142             res = min(res,seq[1]);
143             res = min(res,seq[2] - b[3]);
144             res = min(res,seq[3] - b[3]);
145         }
146         else
147         {
148             res = min(res,seq[pos-1] - b[pos - 2]);
149             if (pos<n)
150             {
151                 res = min(res, seq[pos] - b[pos+1]);
152                 res = min(res, seq[pos+1] - b[pos + 1]);
153             }
154             else
155             {
156                 res = min(res, seq[n]);
157             }
158         }
159         //printf("%lld\n",res);
160         while (res >0)
161         {
162             if (check(pos,res))
163                 break;
164             res--;
165         }
166         return res;
167     }
168     else
169     {
170         //  while (1);
171     }
172     return 0;
173 }
174 
175 /*************以上为暴力对拍**************/
176 
177 
178 int main()
179 {
180     while (scanf("%d",&n)==1)
181     {
182         memset(a,-1,sizeof(a));
183         memset(c,-1,sizeof(c));
184         for (int i=1; i<=n; i++)
185         {
186             scanf("%lld",&a[i]);
187         }
188         for (int i=1; i<=n; i++)
189         {
190             scanf("%lld",&seq[i]);
191         }
192 
193         memset(sum,-1,sizeof(sum));
194         sum[0] = 0;
195         sum[2] = seq[1];
196         for (int i=3; i<=n; i++)
197         {
198             if (i%3 == 1)
199             {
200                 continue;
201             }
202             else
203             {
204                 sum[i] = sum[i-3] + seq[i-1];
205             }
206         }
207         memset(sss,-1,sizeof(sss));
208         sss[n+1] = 0;
209         sss[n-1] = seq[n];
210         for (int i=n-2; i>=1; i--)
211         {
212             if ((n - i+1)%3 == 1)
213             {
214                 continue;
215             }
216             else
217             {
218                 sss[i] = sss[i+3] + seq[i+1];
219             }
220         }
221 
222         memset(b,-1,sizeof(b));
223         for (int i=1; i<=n; i++)
224         {
225             if (i%3 == 0)
226             {
227                 b[i] = sum[i] - sum[i-1];
228             }
229         }
230         for (int i=n; i>=1; i--)
231         {
232             if ((n - i + 1)%3 == 0)
233             {
234                 b[i] = sss[i] - sss[i+1];
235             }
236         }
237 
238 /********以下分类讨论求解***********/
239         if (n % 3 == 2)
240         {
241             //考虑某个非i%3==0的数值确定,那么整个数组也确定。否则求最大最小值
242             int pos = -1;
243             for (int i=1; i<=n; i++)
244             {
245                 if (a[i]!=-1)
246                 {
247                     if (b[i]!=-1)
248                     {
249                         while (a[i] != b[i]) {}
250                         continue;
251                     }
252                     else
253                     {
254                         b[i] = a[i];
255                         pos = i;
256                         break;
257                     }
258                 }
259             }
260 
261             if (pos != -1)
262             {
263                 if (pos%3 == 1)
264                 {
265                     b[pos+1] = seq[pos + 1] - b[pos] - b[pos + 2];
266                     for (int i=pos+3; i<=n; i++)
267                     {
268                         b[i] = seq[i - 1] - b[i-1] - b[i-2];
269                     }
270                     for (int i = pos - 1; i>=1; i--)
271                     {
272                         b[i] = seq[i+1] - b[i+1] - b[i+2];
273                     }
274                 }
275                 else
276                 {
277                     b[pos-1] = seq[pos] - b[pos] - b[pos + 1];
278                     for (int i=pos+2; i<=n; i++)
279                     {
280                         b[i] = seq[i-1] - b[i-1] - b[i-2];
281                     }
282                     for (int i=pos-1; i>=1; i--)
283                     {
284                         b[i] = seq[i+1] - b[i+1] - b[i+2];
285                     }
286                 }
287             }
288             else
289             {
290                 //求最大最小值
291                 int cnt = 0;
292                 memset(bb,-1,sizeof(bb));
293                 b[0] = 0;
294                 for (int i=1; i<n; i++)
295                 {
296                     if (i%3==1)
297                     {
298                         bb[++cnt] = seq[i] - b[i-1];
299                     }
300                     else if (i %3==2)
301                     {
302                         bb[++cnt] = seq[i+1] - b[i+1];
303                     }
304                 }
305                 ff[0] = 0;
306                 for (int i=1; i<=cnt; i++)
307                 {
308                     ff[i] = bb[i] - ff[i-1];
309                    // printf("ff%d = %lld\n",i,ff[i]);
310                 }
311 
312                 c[1] = seq[1];
313                 for (int i=1; i<=cnt; i++)
314                 {
315                     if(i % 2 ==1)
316                     {
317                         c[1] = min(c[1],ff[i]);
318                     }
319                 }
320               //  printf("c = %lld\n",c[1]);
321                 c[2] = seq[1] - c[1];
322                 for (int i=3; i<=n; i++)
323                 {
324                     c[i] = seq[i-1] - c[i-1] - c[i-2];
325                 }
326 
327 
328                 d[1] = 0;
329                 for (int i=1; i<=cnt; i++)
330                 {
331                     if (i%2==0)
332                     {
333                         if (ff[i]<0)
334                         {
335                             d[1] = max(d[1], -ff[i]);
336                         }
337                     }
338                 }
339                // printf("c = %lld = %lld\n",c[1],d[1]);
340                 d[2] = seq[1] - d[1];
341                 for (int i=3; i<=n; i++)
342                 {
343                     d[i] = seq[i-1] - d[i-1] - d[i-2];
344                 }
345                 //  printf("%lld %lld\n",d[1],d[2]);
346             }
347         }
348         else if (n % 3 == 1)
349         {
350             b[1] = seq[2] - b[2] - b[3];
351             for (int i=4; i<=n; i++)
352             {
353                 if (i % 3 == 1)
354                 {
355                     b[i] = seq[i-1] - b[i-1] - b[i-2];
356                 }
357             }
358         }
359         else
360         {
361             b[2] = seq[2] - b[1] - b[3];
362             for (int i=5; i<=n; i++)
363             {
364                 if (i % 3 == 2)
365                 {
366                     b[i] = seq[i-1] - b[i-1] - b[i-2];
367                 }
368             }
369         }
370         scanf("%d",&m);
371         for (int i=1; i<=m; i++)
372         {
373             int id;
374             scanf("%d",&id);
375             id++;
376             if (b[id]!=-1)
377             {
378                 printf("%lld\n",b[id]);
379             }
380             else
381             {
382                 //LL tmp = solve(id);
383                 LL tmp1 = -1;
384                 if (id % 3==1)
385                 {
386                     tmp1 = c[id];
387                 }
388                 else
389                 {
390                     tmp1 = d[id];
391                 }
392                 //printf("%lld tmp1 = %lld\n",tmp,tmp1);
393                 printf("%lld\n",tmp1);
394             }
395         }
396     }
397     return 0;
398 }
Changsha J题

 

 

转载于:https://www.cnblogs.com/wangsouc/articles/3335163.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值