20130820 【南华大学 ACM】 个人选拔赛第二场 【C . DOBRI】

Problem C: DOBRI

Time Limit: 1 Sec   Memory Limit: 32 MB

Description

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行。


  1. 15行实际就是 i 之前(包含 i ),的任意两数之和( 即 b + c ,当 j = i ,为第 i 个的2倍 ),标记为 1;
  2. 接着运算( i++ ),重新回到14行; 
  3. 则此前标记的均是 i 之前任意两数的搭配(b + c );
  4. 这时搜索的 j ,实为遍历 a 的值,当 x - a = b + c 时,就会找到标记的 1 (下标相同,就能调用该位置的储存值);
  5. 退出搜索( 只要有 一种满足 x = a + b + c 的情况即可 );
  6. 重新用当前的 x 作为 b, c 中的一员,重新补充 b + c 的组合情况。
  7. 再次 遍历 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;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值