• csu 2014 summer trainning day 1 哈希


    POJ 1200

    题意:给定串s,串中不同字符数nc,所求子串长度n,求长度为n的不同的子串的个数

    分析:处理长度很短的字符串哈希,数据保证可以无冲突存储下来,利用hash思想快速查询以前便利的结果,关键在于优化搜索。

    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
    ",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 1635

    题意:给定一棵有根树的最小表示,即便利的结果,远离树根表示0,靠近树根表示1,给定两串不同便得到的01序列,判断两棵树是否是同构的。

    分析:1、判断树同构的方法,统计F(x),表示子节点数为x的节点的个数,若两个树的F(x)在定义域内是完全相等的,则两棵树同构。

            2、分析01串:在纸上举几个例子,就能得到规律。便利的结果是满足栈的结构的,所以处理出每个节点在串中出现(一个0,一个1)的两个位置,

    那么这两个位置对应的节点的子节点的个数就是,字符串中这两个位置夹的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
    ",ans);
    52     }
    53     return 0;
    54 }
    View Code

    POJ 2002

    题意:给定1000个二维坐标节点,判断它们能构成多少个正方形。

    分析:1、不造为什么用上一题类似的方法会错???当然,要满足两个垂直一个重合

             2、首先所有点(X^2+Y^2)%Mod哈希存一遍code

             3、用到数学知识:

    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
    ",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
    ",m);
    64     }
    65     return 0;
    66 }
    View Code

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

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

     
  • 相关阅读:
    表示数值的字符串
    正则表达式匹配
    删除链表中重复的结点
    数值的整数次方
    [CSP-S模拟测试]:大新闻(主席树)
    [CSP-S模拟测试]:密码(AC自动机+DP)
    [CSP-S模拟测试]:壕游戏(费用流)
    [CSP-S模拟测试]:山洞(DP+快速幂)
    [CSP-S模拟测试]:阴阳(容斥+计数+递推)
    [CSP-S模拟测试]:虎(DFS+贪心)
  • 原文地址:https://www.cnblogs.com/little-w/p/3852766.html
Copyright © 2020-2023  润新知