1282 时钟(最小表示法+hash)

题目来源: Codility
基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
有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



//思路是有的,但是最小表示法不知道,一只wa。。。学习了最小表示法,还是很好理解的
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define INF 0x3f3f3f3f
 4 #define LL long long
 5 #define MX 505
 6 
 7 const int hash_ = 133331;
 8 
 9 int n, m, p;
10 int ans;
11 int ke[MX];
12 int cha[MX];
13 map<LL,int> zz;
14 
15 int get_min(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 void calc()
34 {
35     sort(ke,ke+m);
36     for (int i=1;i<m;i++)
37         cha[i-1] = ke[i]-ke[i-1];
38     cha[m-1] = ke[0]+p-ke[m-1];
39     int dex= get_min(cha,m);
40 
41     LL has=0, quan =1;
42     for (int i=0;i<m;i++)
43     {
44         has += cha[(dex+i)%m]*quan;
45         quan*= hash_;
46     }
47     ans+=zz[has];
48     zz[has]++;
49 }
50 
51 int main()
52 {
53     scanf("%d%d%d",&n,&m,&p);
54     ans = 0;
55     for (int i=0;i<n;i++)
56     {
57         for (int j=0;j<m;j++)
58             scanf("%d",&ke[j]);
59         calc();
60     }
61     printf("%d\n",ans);
62     return 0;
63 }
View Code

 



posted @ 2017-09-28 21:56  happy_codes  阅读(315)  评论(0编辑  收藏  举报