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 }
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 }
題意:給定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 }
題意:給定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 }
題意:給定一集合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 }
列出一些Hash要用到的素數:
prime=997, prime=1999 , prime=7993 , prime=9973, prime=29989, prime=49999,prime=99991