http://acm.hdu.edu.cn/showproblem.php?pid=5183
2 1 1 1 2 1 -1 0
Case #1: Yes. Case #2: No.HintIf input is huge, fast IO method is recommended.
/**
hdu 5183 hash
题目大意: NP?sum(i,j)=ai?ai+1+ai+2+?+(?1)j?iaj,求给定序列中是否有一个子序列得数为k
解题思路:题目数据很大,只能用O(n)的复杂度。看了杭电的解题报告后,很久才理解。我求将序列的后缀和表示出来(sum[0]-sum[1]+sum[2]-……)
然后从后往前枚举所求区间的第一个位置i,若为奇数那么在h1的哈希表中寻找是不是存在sum[i]-k,如果没有将sum[i]插入哈希表。
如果i为偶数那么在h2中寻找-sum[i]-k,将-sum[i]插入哈希表中。
由于哈希表的插入和查寻复杂度接近O(1),因此我们的算法复杂度总体为O(n)
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define LL long long
const int MAXN=1000010;
const int HASH=1000007;
struct HASHMAP
{
int head[HASH],next[MAXN],ip;
LL state[MAXN];
void init()
{
memset(head,-1,sizeof(head));
ip=0;
}
bool check(LL val)
{
int h=(val%HASH+HASH)%HASH;
for(int i=head[h]; i!=-1; i=next[i])
if(state[i]==val)return true;
return false;
}
int insert(LL val)
{
int h=(val%HASH+HASH)%HASH;
for(int i=head[h]; i!=-1; i=next[i])
{
if(val==state[i])
return 1;
}
state[ip]=val,next[ip]=head[h],head[h]=ip++;
return 0;
}
} h1,h2;
LL a[MAXN];
int n,k;
int main()
{
int T,tt=0;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
for(int i=0; i<n; i++)
scanf("%I64d",&a[i]);
bool flag=false;
LL sum=0;
h1.init(),h2.init();
h1.insert(0),h2.insert(0);
for(int i=n-1; i>=0; i--)
{
if(flag==true)break;
if(i&1)
sum-=a[i];
else
sum+=a[i];
if(i%2==0)
{
if(h1.check(sum-k))
flag=true;
}
else
{
if(h2.check(-sum-k))
flag=true;
}
h1.insert(sum);
h2.insert(-sum);
}
printf("Case #%d: ",++tt);
if(flag)printf("Yes.\n");
else printf("No.\n");
}
return 0;
}
原文:http://blog.csdn.net/lvshubao1314/article/details/44207259