csu 2014 summer trainning day 1 哈希

POJ 1200ios

題意:給定串s,串中不一樣字符數nc,所求子串長度n,求長度爲n的不一樣的子串的個數c++

分析:處理長度很短的字符串哈希,數據保證能夠無衝突存儲下來,利用hash思想快速查詢之前便利的結果,關鍵在於優化搜索。ide

code:優化

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <set>
 5 using namespace std;
 6 
 7 int c[270];
 8 bool Hash[13000000];
 9 char s[1000100];
10 int d,l;
11 void init(int len){
12    memset(c,0,sizeof(c));
13    memset(Hash,0,sizeof(Hash));
14    int cnt=0;
15    for(int i=0;i<len;i++){
16         if (c[s[i]]==0){
17             c[s[i]]=++cnt;
18         }
19         if (cnt==d) break;
20    }
21    return ;
22 }
23 void solve(int len){
24     int ans=0;
25     int v=0;
26     int p=1;
27     for(int i=1;i<l;i++) p*=d;
28     for(int i=0;i<l;i++){
29         v=v*d+c[s[i]];
30     }
31     Hash[v]=true;
32     ans++;
33     for(int i=l;i<len;i++){
34         v=(v-c[s[i-l]]*p)*d+c[s[i]];
35         if (!Hash[v]){
36             ans++;
37             Hash[v]=true;
38         }
39     }
40     printf("%d\n",ans);
41     return ;
42 }
43 int main(){
44     while(~scanf("%d%d",&l,&d)){
45         scanf("%s",s);
46         int len=strlen(s);
47         init(len);
48         solve(len);
49     }
50     return 0;
51 }
View Code

POJ 1635spa

題意:給定一棵有根樹的最小表示,即使利的結果,遠離樹根表示0,靠近樹根表示1,給定兩串不一樣便獲得的01序列,判斷兩棵樹是不是同構的。code

分析:一、判斷樹同構的方法,統計F(x),表示子節點數爲x的節點的個數,若兩個樹的F(x)在定義域內是徹底相等的,則兩棵樹同構。orm

        二、分析01串:在紙上舉幾個例子,就能獲得規律。便利的結果是知足棧的結構的,因此處理出每一個節點在串中出現(一個0,一個1)的兩個位置,blog

那麼這兩個位置對應的節點的子節點的個數就是,字符串中這兩個位置夾的0(或1)的個數。預處理O(n),統計O(n)排序

code:字符串

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <set>
 5 #include <stack>
 6 using namespace std;
 7 
 8 int t;
 9 char s1[3010],s2[3010];
10 int px1[3010],py1[3010];
11 int px2[3010],py2[3010];
12 int num1[3010],num2[3010];
13 int cnt1,cnt2,len;
14 int S[3010],p;//手動開的棧
15 bool check(){
16     memset(num1,0,sizeof(num1));
17     memset(num2,0,sizeof(num2));
18     for(int i=1;i<=cnt1;i++){
19         int x=px1[i];
20         int y=py1[i];
21         int c=0;
22         for(int i=x+1;i<y;i++){
23             if (s1[i]=='0') c++;
24         }
25         num1[c]++;
26     }
27     for(int i=1;i<=cnt2;i++){
28         int x=px2[i];
29         int y=py2[i];
30         int c=0;
31         for(int i=x+1;i<y;i++){
32             if (s2[i]=='0') c++;
33         }
34         num2[c]++;
35     }
36     for(int i=0;i<=cnt2;i++){
37         if (num1[i]!=num2[i]) return false;
38     }
39     return true;
40 }
41 void solve(){
42     len=strlen(s1);
43     if (len!=(int)strlen(s2)){
44         puts("different");
45         return ;
46     }
47     cnt1=0;p=0;
48     for(int i=0;i<len;i++){
49         if(s1[i]=='0'){
50             S[++p]=++cnt1;
51             px1[cnt1]=i;
52         }
53         if (s1[i]=='1'){
54             py1[S[p--]]=i;
55         }
56     }
57 ////    for(int i=1;i<=cnt1;i++){
58 ////        cout<<px1[i]<<" "<<py1[i]<<endl;
59 ////    }
60     cnt2=0;p=0;
61     for(int i=0;i<len;i++){
62         if(s2[i]=='0'){
63             S[++p]=++cnt2;
64             px2[cnt2]=i;
65         }
66         if (s2[i]=='1'){
67             py2[S[p--]]=i;
68         }
69     }
70     if (cnt1!=cnt2) {
71         puts("different");
72         return ;
73     }
74     if (check()){
75         puts("same");
76     }else puts("different");
77 
78     return ;
79 }
80 int main(){
81     scanf("%d",&t);
82     while(t--){
83         scanf("%s",s1);
84         scanf("%s",s2);
85         solve();
86     }
87     return 0;
88 }
View Code

POJ 1971

題意:給定1000個二維座標節點,判斷這些節點能構成的平行四邊形有多少個。座標範圍<=1000000000

分析:數學知識是必要的,否則很難想到很快的搜索辦法(反正開始時我沒有),即平行四邊形的兩對對頂點的的中點是重合的。

那麼,若存在兩個重合的中點,那麼這兩條邊交叉起來能構成一個平行四邊形。

       那麼咱們O(n^2)枚舉任意兩個點,處理出他們的中點(處理成整數,不除2)。

      獲得n^2/2箇中點的咱們如今要能快速找找到對於每種中點有幾個是相等的。這道題不使用hash,排序後,成段掃描處理便可,固然,Hash更快。

 1 #include <iostream>
 2 #include <queue>
 3 #include <string.h>
 4 #include <stdio.h>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 int t,n;
 9 int x[1100],y[1100];
10 struct N{
11     int x,y;
12     bool operator <(const N&X)const{
13         if (x==X.x) return y<X.y;
14         else return x<X.x;
15     }
16     bool operator==(const N&X)const{
17         return x==X.x&&y==X.y;
18     }
19 
20 }Ps[1100000];
21 void print(int cnt){
22         for(int i=0;i<cnt;i++){
23             cout<<"("<<Ps[i].x<<","<<Ps[i].y<<")"<<endl;
24         }
25     }
26 int cnt;
27 int main(){
28     scanf("%d",&t);
29     while(t--){
30         scanf("%d",&n);
31         for(int i=0;i<n;i++){
32             scanf("%d%d",&x[i],&y[i]);
33         }
34         cnt=0;
35         for(int i=0;i<n-1;i++){
36             for(int j=i+1;j<n;j++){
37                 Ps[cnt++]=(N){x[i]+x[j],y[i]+y[j]};
38             }
39         }
40         sort(Ps,Ps+cnt);
41         long long ans=0;
42         int k=1;
43         for(int i=1;i<cnt;i++){
44             if (Ps[i]==Ps[i-1]){
45                 k++;
46             }else{
47                 ans=ans+(long long)k*(k-1)/2;
48                 k=1;
49             }
50         }
51         printf("%I64d\n",ans);
52     }
53     return 0;
54 }
View Code

POJ 2002

題意:給定1000個二維座標節點,判斷它們能構成多少個正方形。

分析:一、不造爲何用上一題相似的方法會錯???固然,要知足兩個垂直一個重合

         二、首先全部點(X^2+Y^2)%Mod哈希存一遍code

         三、用到數學知識:

Point A=(Point){x[i]-y[i]+y[j],y[i]+x[i]-x[j]}; Point B=(Point){x[j]-y[i]+y[j],y[j]+x[i]-x[j]}; Point C=(Point){x[i]+y[i]-y[j],y[i]-x[i]+x[j]}; Point D=(Point){x[j]+y[i]-y[j],y[j]-x[i]+x[j]};
枚舉兩點,公式求出另外兩點,Hash查找這些點是否在圖上,統計出個數,用組合數學便可處理
code:
 1 #include <iostream>
 2 #include <queue>
 3 #include <string.h>
 4 #include <stdio.h>
 5 #include <algorithm>
 6 #define Mod 49999
 7 using namespace std;
 8 struct Point{
 9     int x,y;
10     int k;
11     bool operator==(const Point&X){
12         return x==X.x&&y==X.y;
13     }
14 };
15 vector<Point>G[Mod+100];
16 
17 void init(){
18     for(int i=0;i<Mod+10;i++) G[i].clear();
19 }
20 
21 int Hash(Point P){
22     return (P.x*P.x+P.y*P.y)%Mod;
23 }
24 
25 int findx(Point P){
26     int ha=Hash(P);
27     int i;
28     for(i=0;i<G[ha].size();i++){
29         if (G[ha][i]==P) break;
30     }
31     if (i==G[ha].size()) return 0;
32     return G[ha][i].k;
33 }
34 void Insert(Point P){
35     int ha=Hash(P);
36     int i;
37     for(i=0;i<G[ha].size();i++){
38         if (G[ha][i]==P) {
39             G[ha][i].k++;
40             break;
41         }
42     }
43     if (i==G[ha].size()){
44         G[ha].push_back((Point){P.x,P.y,1});
45     }
46     return ;
47 }
48 
49 int n;
50 int x[1100],y[1100];
51 int main(){
52     while(~scanf("%d",&n)&&n){
53         init();
54         for(int i=0;i<n;i++){
55             scanf("%d%d",&x[i],&y[i]);
56             Insert((Point){x[i],y[i],0});
57         }
58         int ans=0;
59         for(int i=0;i<n-1;i++){
60             for(int j=i+1;j<n;j++){
61                 Point A=(Point){x[i]-y[i]+y[j],y[i]+x[i]-x[j]};
62                 Point B=(Point){x[j]-y[i]+y[j],y[j]+x[i]-x[j]};
63                 Point C=(Point){x[i]+y[i]-y[j],y[i]-x[i]+x[j]};
64                 Point D=(Point){x[j]+y[i]-y[j],y[j]-x[i]+x[j]};
65                 int k1=findx(C);
66                 int k2=findx(D);
67                 int k3=findx(A);
68                 int k4=findx(B);
69                 ans+=(k1*k2)+(k3*k4);
70             }
71         }
72         ans=ans/4;
73         printf("%d\n",ans);
74     }
75     return 0;
76 }
View Code

POJ 2549

題意:給定一集合S,給定集合中的全部數,統計A+B+C=D的個數,A、B、C、D皆取自S,且是各不相同的元素。集合的元素的個數<=1000

分析: 相似白書上的中途相遇法,等式能夠這樣看,A+B=D-C,兩兩枚舉,Hash存儲,再兩兩枚舉D,A,統計便可。注意存的時候,要保留A、B,

      由於A、B、C、D要不相同,因此要判斷。

code:

 1 #include <iostream>
 2 #include <queue>
 3 #include <string.h>
 4 #include <stdio.h>
 5 #include <algorithm>
 6 #include <vector>
 7 #define Mod 49999
 8 
 9 using namespace std;
10 struct Node{
11     int add,a1,a2;
12 };
13 vector<Node>G[Mod+100];
14 void init(){
15     for(int i=0;i<Mod+10;i++) G[i].clear();
16 }
17 void Insert(int k,int b1,int b2){
18     int key=k;
19     while(key<0) key=key+Mod;
20     key=key%Mod;
21     int i;
22     for(i=0;i<G[key].size();i++){
23         int add=G[key][i].add;
24         int a1=G[key][i].a1;
25         int a2=G[key][i].a2;
26         if (add == k && (a1+a2==b1+b2) && (a1-a2==b1-b2)) break;
27     }
28     if (i==G[key].size()) G[key].push_back(Node{k,b1,b2});
29     return ;
30 }
31 bool Search(int d,int c){
32     int key=d-c;
33     while(key<0) key=key+Mod;
34     key=key%Mod;
35     int i;
36     for(i=0;i<G[key].size();i++){
37         int add=G[key][i].add;
38         int a1=G[key][i].a1;
39         int a2=G[key][i].a2;
40         if (add==d-c && a1!=d && a2!=d && a1!=c && a2!=c) return true;
41     }
42     return false;
43 }
44 int a[1010];
45 int n;
46 int main(){
47     while(~scanf("%d",&n)&&n){
48         init();
49         for(int i=0;i<n;i++) scanf("%d",&a[i]);
50         for(int i=0;i<n-1;i++){
51             for(int j=i+1;j<n;j++){
52                 Insert(a[i]+a[j],a[i],a[j]);
53             }
54         }
55         int m=-536870913;
56         for(int i=0;i<n-1;i++){
57             for(int j=i+1;j<n;j++){
58                 if (Search(a[i],a[j])) m=max(m,a[i]);
59                 if (Search(a[j],a[i])) m=max(m,a[j]);
60             }
61         }
62         if (m==-536870913) puts("no solution");
63         else printf("%d\n",m);
64     }
65     return 0;
66 }
View Code

 

列出一些Hash要用到的素數:

prime=997,  prime=1999 , prime=7993 , prime=9973, prime=29989, prime=49999,prime=99991

相關文章
相關標籤/搜索