hdu 5183 Negative and Positive (NP) (hash大法)

本文介绍了一种解决特定区间和问题的方法,通过计算前缀和并利用哈希表来高效查询是否存在一对下标使得区间的奇偶交替和等于给定值k。文中提供了一个完整的C++实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

给出n个数,这个数一段区间和这样定义 sum[i,j]= ai - ai+1 +......+(-1)^(j-i)aj.给出一个数k,问是否存在一个sum[i,j]==k

题解:

我们手下得出前缀和,然后从后往前推,判断sum[i-1]-k或sum[i-1]+k是否在hash中,然后将sum[i]存入hash。因为题目求的是 sum[j]-sum[i]==k,那么我们将式子变形 sum[i]+k == sum[j] 这样只要判断前者是否在hash中出现就计算了出了i到之后所有j的情况。这题非常坑,读入超时,要手写读入。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<hash_map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
typedef __int64 ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const int MOD=10007;
const int maxn=1000005;
ll sum[maxn];
const int HASH = 1000007;

struct HASHMAP
{
    int head[HASH],next[maxn],size;
    long long state[maxn];
    void init()
    {
        size = 0;
        memset(head,-1,sizeof(head));
    }
    bool check(long long val){
        int h = (val%HASH+HASH)%HASH;
        for(int i = head[h];i != -1;i = next[i])
            if(val == state[i])
                return true;
        return false;
    }
    int insert(long long val)
    {
        int h = (val%HASH+HASH)%HASH;
        for(int i = head[h]; i != -1;i = next[i])
            if(val == state[i])
            {
                return 1;
            }
        state[size] = val;
        next[size] = head[h];
        head[h] = size++;
        return 0;
    }
}mat;

template <class T>
inline bool read(T &ret) {
   char c; int sgn;
   if(c=getchar(),c==EOF) return 0; //EOF
   while(c!='-'&&(c<'0'||c>'9')) c=getchar();
   sgn=(c=='-')?-1:1;
   ret=(c=='-')?0:(c-'0');
   while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
   ret*=sgn;
   return 1;
}

int main(){

    int n,k,T,sig,f;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++){

        mat.init();
        sig=1;f=0;
        read(n);
        read(k);
        sum[0]=0;
        for(int i=1;i<=n;i++){

            read(sum[i]);
            sum[i]=sum[i-1]+sig*sum[i];
            sig*=-1;
        }
        mat.insert(sum[n]);
        for(int i=n;i>=1&&f==0;i--){

            if(i&1){
                if(mat.check(sum[i-1]+k))f=1;
            }else{
                if(mat.check(sum[i-1]-k))f=1;
            }
            mat.insert(sum[i-1]);
        }
        if(f)printf("Case #%d: Yes.\n",cas);
        else printf("Case #%d: No.\n",cas);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值