您的位置:首页 > 其它

2013 ACM/ICPC Asia Regional Changsha Online - J Candies

2013-09-23 12:00 459 查看
题意:

给你一排数,有的数告诉你明确的值,有的数不告诉(用-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
就是满足所有等式的值了,然后往回推回去,就推出一排数了。然后推出使得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
的值,也可以推出所有的值
else if(n % 3 == 1) {
a
= sum
- 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: