思路:题目是根据所给的规则,判断是否在一个区间i-j的结果等于k。
其实要求i-j区间的值我们可以采用1-j的值减去1-i的值即可得到i-j的值。
sum[j]-sum[i]=k
sum[j]-k=sum[i]
问题就可以转化成判断sum[i]是否存在,而sum[i]假如存在的话,一定在求解sum[j]之前求解过了
所以我们不妨将求解过的sum[l]全部假如hash表当中,只要对sum[i]进行判断是否存在即可,不仅方便而且很快。
但是由于题目所给的限制条件。
当i为偶数的时候,相减得到的值就是正确的。所以直接查找sum[j]-k,当然这个时候需要查找的是i为奇数,所以我们还要加入一个变量,确保我们找到的值是一个偶数的前缀和。
但若i为奇数的时候,得到的值则是相反数。
即-(sum[j]-sum[i])=k,转化一下sum[i]=k+sum[j],所以这个时候我们求解的就是sum[j]+k,同样的道理,加入一个变量确保我们求解的时候是一个奇数的前缀和。
详细请看代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#define MAX 4000040
#define mod 1000007
struct pos
{
long long x;
int next;
int po;
}s[MAX];
int head[mod];
int cnt = 0;
void add(long long x,int pos)
{
int h = (x + mod) % mod;
for (int i = head[h]; i != -1;i=s[i].next)
if (s[i].x == x&&pos==s[i].po)return;
s[cnt].po = pos & 1;
s[cnt].x = x;
s[cnt].next = head[h];
head[h] = cnt++;
}
bool ok(long long x,int pos)
{
int h = (x + mod) % mod;
for (int i = head[h]; i != -1; i = s[i].next)
if (s[i].x == x&&pos==s[i].po)return true;
return false;
}
int main()
{
int t;
cin >> t;
int icase = 1;
while (t--)
{
memset(head, -1, sizeof(head));
int n;
long long k;
scanf("%d%lld", &n, &k);
int x;
long long sum = 0;
bool flag = 0;
add(0, 0);//我们要的是正好是一个前缀的时候,
for (int i = 1; i <=n; i++)
{
scanf("%d", &x);
if (i & 1)
sum += x;//之前给写反了,就超时了
else
sum -= x;
if (!flag)
{
if (ok(sum - k,0))flag = true;
if (ok(sum + k, 1))flag = true;
add(sum, i);
}
}
printf("Case #%d: %s\n",icase++, flag ? "Yes." : "No.");
}
}