zoukankan      html  css  js  c++  java
  • HDU 5183 Negative and Positive (NP) --Hashmap

    题意:问有没有数对(i,j)(0<=i<=j<n),使得a[i]-a[i+1]+...+(-1)^(j-i)a[j]为K.

    解法:两种方法,枚举起点或者枚举终点。

    先保存前缀和:a1-a2+a3....+/- an

    枚举起点法: 设起点为x,实际是枚举x-1,分两种情况:

    1.起点x为奇,那么就看有没有a[j]-a[x-1] = K的,即a[j] = a[x-1]+K。因为奇数位置的ai数符为正。

    2.起点x为偶,那么就看有没有a[j]-(-K) = a[x-1],即a[j] = a[x-1]-K。因为偶数位置ai数符为负,即x到j这一段的数是负的 选x为起点的x到j的这一段和,所以中间实际上是-K。

    每次将sum[i]标记为出现过。

    只需要一个hashmap即可。

    由于枚举到一个起点x,需要判断a[j](j>x)是否出现,所以要逆序枚举。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #define Mod 1000000007
    #define lll __int64
    #define ll long long
    using namespace std;
    #define N 1000007
    
    lll sum[N];
    const unsigned long long SMod=1000007;
    struct hashmap{
        struct Edge
        {
            long long num;
            int next;
        };
        Edge edge[2*N];
        int countedge;
        int head[SMod+100];
    
        void init()
        {
            memset(head,-1,sizeof(head));
            countedge=0;
        }
    
        void addedge(long long num)
        {
            int start=num%SMod;
            edge[countedge].next=head[start];
            edge[countedge].num=num;
            head[start]=countedge;
            countedge++;
        }
    
        int Find(long long num)
        {
            int start=num%SMod;
            int ind;
            for(ind=head[start]; ind!=-1; ind=edge[ind].next)
            {
                if(edge[ind].num==num)break;
            }
            return ind;
        }
    }ST;
    
    int main()
    {
        int n,i,j,cs = 1,t,x,K;
        scanf("%d",&t);
        while(t--)
        {
            ST.init();
            scanf("%d%d",&n,&K);
            sum[0] = 0;
            for(i=1;i<=n;i++) {
                scanf("%d",&x);
                if(i%2) sum[i] = sum[i-1] + x;
                else    sum[i] = sum[i-1] - x;
            }
            ST.addedge(sum[n]);
            int tag = 0;
            for(i=n-1;i>=0;i--) {
                if(i%2 == 0 && ST.Find(sum[i]+K) != -1) { tag = 1; break; }
                if(i%2 && ST.Find(sum[i]-K) != -1) { tag = 1; break; }
                ST.addedge(sum[i]);
            }
            printf("Case #%d: ",cs++);
            if(tag) puts("Yes.");
            else    puts("No.");
        }
        return 0;
    }
    View Code

    枚举终点法

    建立两个hashmap,一个记录sum[1],sum[3],...sum[2*cnt+1] (2*cnt+1<=n)即奇数位置是否出现过,另一个记录偶数位置的sum值是否出现过。

    枚举终点y的话,起点可能是1~y的任何一个(这里下标从题目中的0~n-1转为了1~n),当起点x=1的时候,这时NP-SUM(x,y) = sum[y], 记为XX。以n=4为例。

    那么起点为2的时候整个值就等于 -XX+a1, (-(a1-a2+a3-a4) +a1 = a2-a3+a4))

    起点为3的时候整个值等于 XX-sum[2]      (a1-a2+a3-a4 - (a1-a2) = a3-a4 )

    ...以此类推,归为两类 :

    1. XX-sum[0] , XX-sum[2] , ... XX-sum[偶数] 是否为K

    2. -XX+sum[1], -XX+sum[3], ... -XX+sum[奇数] 是否为K

    设他们为K,那么即判断 XX-K在偶数的hashmap中有没有出现, 判断XX+K在奇数的hashmap中有没有出现。

    每次将sum[i]加入到对应的hashmap中。

    顺序枚举。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #define Mod 1000000007
    #define lll __int64
    #define ll long long
    using namespace std;
    #define N 1000007
    
    const unsigned long long SMod=1000007;
    struct hashmap{
        struct Edge
        {
            long long num;
            int next;
        };
        Edge edge[2*N];
        int countedge;
        int head[SMod+100];
    
        void init()
        {
            memset(head,-1,sizeof(head));
            countedge=0;
        }
    
        void addedge(long long num)
        {
            int start=num%SMod;
            edge[countedge].next=head[start];
            edge[countedge].num=num;
            head[start]=countedge;
            countedge++;
        }
    
        int Find(long long num)
        {
            int start=num%SMod;
            int ind;
            for(ind=head[start]; ind!=-1; ind=edge[ind].next)
            {
                if(edge[ind].num==num)break;
            }
            return ind;
        }
    }mpe,mpo;
    
    int main()
    {
        int n,i,j,cs = 1,t,x,K;
        scanf("%d",&t);
        for(cs=1;cs<=t;cs++)
        {
            mpo.init();
            mpe.init();
            scanf("%d%d",&n,&K);
            lll sum = 0;
            mpe.addedge(0);
            int tag = 0;
            for(i=1;i<=n;i++) {
                scanf("%d",&x);
                if(i&1) sum += x;
                else    sum -= x;
                if(i&1) mpo.addedge(sum);
                else    mpe.addedge(sum);
                if(mpe.Find(sum-K) != -1) { tag = 1; }
                if(mpo.Find(sum+K) != -1) { tag = 1; }
            }
            printf("Case #%d: ",cs);
            if(tag) puts("Yes.");
            else    puts("No.");
        }
        return 0;
    }
    View Code

    注意: 

    如果hashmap中的SMod 用宏定义的方式就会T, 用const unsigned long long 就不会。不知道为什么。

    hashmap模板借鉴了love_dn的代码。

  • 相关阅读:
    lua时间戳和日期转换及踩坑【转】
    Js正则表达式验证输入是否有特殊字符【转】
    PHP数据类型转换【转】
    JavaScript indexOf() 方法
    CSS文本下划线 删除线 上划线【转】
    PHP中把stdClass Object转array的几个方法【转】
    2020软件工程作业02
    2020软件工程作业01
    2020 CCPC Wannafly Winter Camp Day1-F-乘法
    牛客-装货物
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4321769.html
Copyright © 2011-2022 走看看