51Nod 1282 时钟 —— 最小表示法 + 字符串哈希
题目链接:https://vjudge.net/problem/51Nod-1282
有N个时钟,每个时钟有M个指针,P个刻度。时钟是圆形的,P个刻度均分整个圆。每个时钟每个指针指向整数刻度,并且每个时钟自身指针指向的数字都不同。你可以任意旋转时钟的表盘,但是你不能转指针。问最后有多少对时钟可以变成相同的状态。
例如:N = 5,M = 2,P = 4,5个时钟的数据如下{1, 2} {2, 4} {4, 3} {2, 3} {1, 3}
经过旋转后。 其中(1, 3), (1, 4), (2, 5) 和 (3, 4)是相同的。
给出所有时钟的数据,求有多少对时钟是相同的。
Input
第1行:3个数N, M, P中间用空格分隔,其中N为时钟的数量,M为表针的数量,P为刻度的数量(1 <= M, N <= 500, 1 <= P <= 10^9, M <= P)。 第2 - N + 1行:每行M个数,对应一个时钟,M个指针的位置。
Output
输出有多少对时钟是相同的。
Input示例
5 2 4 1 2 2 4 4 3 2 3 1 3
Output示例
4
题解:
1.对于每个时钟,计算所有相邻时针的间隔,然后用最小表示法表示。
2.借助字符串哈希,将每个经过最小表示法处理后的时钟压缩成一个unsigne long long类型的数。
3.使用map维护。
代码如下:
1 #include <bits/stdc++.h> 2 #define rep(i,a,n) for(int (i) = a; (i)<=(n); (i)++) 3 #define ms(a,b) memset((a),(b),sizeof((a))) 4 using namespace std; 5 typedef long long LL; 6 const int INF = 2e9; 7 const LL LNF = 9e18; 8 const int mod = 1e9+7; 9 const int maxn = 500+10; 10 11 int a[maxn][maxn]; 12 int n,m,p; 13 map<unsigned long long, int >mp; 14 const unsigned long long seed = 13331; 15 16 int getmin(int *s, int len) //返回最小表示法的始端 17 { 18 int i = 0, j = 1, k = 0; 19 while(i<len && j<len && k<len) 20 { 21 int t = s[(i+k)%len]-s[(j+k)%len]; 22 if (!t) k++; 23 else 24 { 25 if (t>0) i += k+1; 26 else j += k+1; 27 if (i==j) j++; 28 k = 0; 29 } 30 } 31 return i<j?i:j; 32 } 33 34 int main() 35 { 36 int ans = 0; 37 cin>>n>>m>>p; 38 for(int i = 0; i<n; i++) 39 { 40 for(int j = 0; j<m; j++) 41 cin>>a[i][j]; 42 43 sort(a[i], a[i]+m); 44 a[i][m] = a[i][0]+p; 45 for(int j = 0; j<m; j++) //获得间隔距离 46 a[i][j] = a[i][j+1]-a[i][j]; 47 48 int k = getmin(a[i], m); //k为始端 49 unsigned long long s = 1; 50 for(int j = 0; j<m; j++) 51 { 52 int t = (j+k)%m; 53 s = 1LL*s*seed + 1LL*a[i][t]; //字符串哈希,seed相当于进制 54 } 55 ans += mp[s]; //统计对数 56 mp[s]++; //加入到map中 57 } 58 cout<<ans<<endl; 59 }
一开始没有用字符串哈希,直接把数组用队列的形式丢进map中,也不会超内存。
1 #include <bits/stdc++.h> 2 #define rep(i,a,n) for(int (i) = a; (i)<=(n); (i)++) 3 #define ms(a,b) memset((a),(b),sizeof((a))) 4 using namespace std; 5 typedef long long LL; 6 const int INF = 2e9; 7 const LL LNF = 9e18; 8 const int mod = 1e9+7; 9 const int maxn = 500+10; 10 11 int a[maxn][maxn]; 12 int n,m,p; 13 map< queue<int>, int >mp; //把数组以队列的形式丢进map中 14 15 int getmin(int *s, int len) 16 { 17 int i = 0, j = 1, k = 0; 18 while(i<len && j<len && k<len) 19 { 20 int t = s[(i+k)%len]-s[(j+k)%len]; 21 if (!t) k++; 22 else 23 { 24 if (t>0) i+=k+1; 25 else j+=k+1; 26 if (i==j) j++; 27 k=0; 28 } 29 } 30 return i<j?i:j; 31 } 32 33 34 int main() 35 { 36 int ans = 0; 37 cin>>n>>m>>p; 38 for(int i = 0; i<n; i++) 39 { 40 for(int j = 0; j<m; j++) 41 cin>>a[i][j]; 42 43 sort(a[i], a[i]+m); 44 a[i][m] = a[i][0]+p; 45 for(int j = 0; j<m; j++) 46 a[i][j] = a[i][j+1]-a[i][j]; 47 48 int k = getmin(a[i], m); 49 queue<int>v; 50 for(int j = 0; j<m; j++) 51 { 52 int t = (j+k)%m; 53 v.push(a[i][t]); 54 } 55 ans += mp[v]; 56 mp[v]++; 57 } 58 cout<<ans<<endl; 59 }