HDU 5183 Negative and Positive (NP) --Hashmap

題意:問有沒有數對(i,j)(0<=i<=j<n),使得a[i]-a[i+1]+...+(-1)^(j-i)a[j]爲K.ios

解法:兩種方法,枚舉起點或者枚舉終點。ide

先保存前綴和:a1-a2+a3....+/- anspa

枚舉起點法: 設起點爲x,實際是枚舉x-1,分兩種狀況:code

1.起點x爲奇,那麼就看有沒有a[j]-a[x-1] = K的,即a[j] = a[x-1]+K。由於奇數位置的ai數符爲正。blog

2.起點x爲偶,那麼就看有沒有a[j]-(-K) = a[x-1],即a[j] = a[x-1]-K。由於偶數位置ai數符爲負,即x到j這一段的數是負的 選x爲起點的x到j的這一段和,因此中間其實是-K。string

每次將sum[i]標記爲出現過。hash

只須要一個hashmap便可。it

因爲枚舉到一個起點x,須要判斷a[j](j>x)是否出現,因此要逆序枚舉。io

代碼:event

#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的代碼。

相關文章
相關標籤/搜索