Problem C: DOBRI
Time Limit: 1 Sec Memory Limit: 32 MBDescription
You are given a sequence A consisting of N integers (not to be confused with the sequence from the
previous task). We will call the i
th
sequence element good if it equals the sum of some three elements
in positions strictly smaller than i (an element can be used more than once in the sum).
How many good elements does the sequence contain?
Input
The first line of input contains the positive integer N (1 ≤ N ≤ 5000), the length of the sequence A.
The second line of input contains N space-separated integers representing the sequence A (-100 000 ≤
Ai ≤ 100 000).
Output
The first and only line of output must contain the number of good elements in the sequence.
Sample Input
2 1 3 6 1 2 3 5 7 10 3 -1 2 0
Sample Output
1 4 1
-----------------------------------------------------------------------------------------------------------------
这题当时做的时候,想用暴力,但是明显会超时。
于是,跳过跳过……
后来参考了大神的代码,仔细分析了一遍。
发现用的方法很奇特。
( 下面的代码是模仿过来的 )
该题求: 是否有 a, b, c 满足 x = a + b + c ( x 为第 i 个数的值; a, b, c 是排在 i 前面的数,可重复 );
因为 ( -100000 <= a, b, c, x <= 100000 ),用数组标记时( 数组下标没有负数 ),要 + 100000 转正;
如果直接用数组标记,范围太大( 0 <= a + b + c <= 600000 ),而且运算次数太多;
但若进行移项, x - a = b + c ,范围为: 0 <= x - a , b + c <= 400000;
下面代码重点与难点就是14,15行;其实理解顺序应该先从15行开始,在理解14行。
- 15行实际就是 i 之前(包含 i ),的任意两数之和( 即 b + c ,当 j = i ,为第 i 个的2倍 ),标记为 1;
- 接着运算( i++ ),重新回到14行;
- 则此前标记的均是 i 之前任意两数的搭配(b + c );
- 这时搜索的 j ,实为遍历 a 的值,当 x - a = b + c 时,就会找到标记的 1 (下标相同,就能调用该位置的储存值);
- 退出搜索( 只要有 一种满足 x = a + b + c 的情况即可 );
- 重新用当前的 x 作为 b, c 中的一员,重新补充 b + c 的组合情况。
- 再次 遍历 a, 寻找 新x - a = b + c 的情况……
-----------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
const int MAX_NUM = 200000;
const int MAX_N = 5000;
int num[ MAX_NUM*2+10 ], n[ MAX_N+10 ];
int main() {
int i, j, t, flag, sum;
while( scanf("%d", &t) != EOF ) {
memset( num, 0, sizeof(num));
memset( n, 0, sizeof(n));
for( i=0; i<t ; ++i )
scanf("%d", &n[i] );
for( sum=0, flag=0, i=0; i<t ; ++i, flag=0 ) {
for( j=0 ; j<i && !flag ; ++j ) flag = num[ n[i] - n[j] + MAX_NUM ];
for( j=0 ; j<=i ; ++j ) num[ n[i] + n[j] + MAX_NUM ] = 1;
sum += flag;
}
printf("%d\n", sum);
}
return 0;
}