题意:
给你一排数,有的数告诉你明确的值,有的数不告诉(用-1来表示),然后给出每个数相邻三个数的和,首尾则是相邻两个数的和,有m次询问,问a[i]最大值是多少。 (比赛的时候太挫了,wa了,后来把某些地方改成简单点形式就A了。)
解题思路:
首先可以得到一列等式:
a1 + a2 = sum1;
a1 + a2 + a3 = sum2;
a2 + a3 + a4 = sum3;
a3 + a4 + a5 = sum4;
a4 + a5 + a6 = sum5;
a5 + a6 + a7 = sum6;
...
由等式容易得知a[i] (i % 3 == 0) 的值都可以明确了,现在把这些等式化简一下得:
a1 + a2 = s1;
a2 + a4 = s2;
a4 + a5 = s3;
a5 + a7 = s4;
a7 + a8 = s5;
...
容易发现,如果我们知道了这些等式中的任何一个未知数的值,其他所有的值都可以确定了。但是如果一个都不知道的话,就要算出每个数最大可能是多大。
举个例子,如果要使得a5最大,则令a4尽量小,a2尽量大,a1尽量小。如果要使得a4尽量大,则a2尽量小,a1尽量大。容易发现,使得a1尽量小和使得a1尽量大后满足所有等式的两排不同的数就是每个数的范围。
比如要使得a1尽量小,然后往下推出所有a[i]满足每个等式,a[n]就是满足所有等式的值了,然后往回推回去,就推出一排数了。然后推出使得a1尽量大的一排数,最后询问的时候直接输出两排数a[i]较大值。
code:
#include <stdio.h> const int maxn = 100000 + 10; int pre[maxn], next[maxn]; int a[maxn], b[maxn], c[maxn], sum[maxn]; int max(int a, int b) { return a>b?a:b; } //等式中相邻的未知数处理next和pre void init(int n) { bool flag = 1; int i = 1; pre[1] = -1; while(i <= n) { if(flag) { next[i] = i+1; pre[i+1] = i; flag = 0; i += 1; } else { next[i] = i+2; pre[i+2] = i; i += 2; flag = 1; } } } int main() { init(100000); int n; while(scanf("%d", &n) != -1) { for(int i = 1;i <= n; i++) scanf("%d", &a[i]); for(int i = 1;i <= n; i++) scanf("%d", &sum[i]); a[0] = a[n+1] = 0; for(int i = 3;i <= n;i += 3) { a[i] = sum[i-1] - sum[i-2] + a[i-3]; } bool flag = 0; // 如果n%3==0,则可以知道a[n-1]的值,就能直接推出所有的值 if(n % 3 == 0) { for(int i = n-1;i >= 1; i--) if(a[i] == -1) a[i] = sum[i+1] - a[i+1] - a[i+2]; flag = 1; } //如果n%3==1,就能知道a[n]的值,也可以推出所有的值 else if(n % 3 == 1) { a[n] = sum[n] - a[n-1]; for(int i = n-2;i >= 1; i--) if(a[i] == -1) a[i] = sum[i+1] - a[i+1] - a[i+2]; flag = 1; } else { for(int i = 1;i <= n; i++) if((i % 3 != 0) && a[i] != -1) { //如果有一个未知数知道了,其他都可以确定了 b[i] = a[i]; for(int j = i-1;j >= 1; j--) if(a[j] == -1) a[j] = sum[j+1] - a[j+1] - a[j+2]; for(int j = i+1;j <= n; j++) if(a[j] == -1) a[j] = sum[j-1] - a[j-1] - a[j-2]; flag = 1; break; } if(!flag) { int now = 1; b[1] = 0; c[1] = sum[1]; // b[i]:令a[1]尽量小的一排数 // c[i]: 令a[1]尽量大的一排数 while(now <= n) { int ne = next[now]; if(ne - now == 2) { b[ne] = sum[now+1] - a[now+1] - b[now]; c[ne] = sum[now+1] - a[now+1] - c[now]; } else { b[ne] = sum[ne] - a[ne+1] - b[now]; c[ne] = sum[ne] - a[ne+1] - c[now]; } // 注意如果有个数为负数,不过值最小为0,不能为负的 if(b[ne] < 0) b[ne] = 0; if(c[ne] < 0) c[ne] = 0; now = ne; } now = n; for(int i = 0;i < n; i++) b[i] = c[i] = a[i]; for(int i = n-1;i >= 1; i--) if(b[i] == -1) { b[i] = sum[i+1] - b[i+1] - b[i+2]; c[i] = sum[i+1] - c[i+1] - c[i+2]; } } } int m, x; scanf("%d", &m); while(m--) { scanf("%d", &x); x++; if(flag) printf("%d\n", a[x]); else { int ans = max(b[x], c[x]); printf("%d\n", ans); } } } return 0; }