51nod 1282 时钟 哈希+最小表示法+map

有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
 
  
首先对于询问有多少对相同的,我们只需要对当前表看看之前有没有相同的,如果有,就ans加上那个相同的个数即可。这样来计算。
对于每个表,我们要进行哈希处理。如何哈希呢,题目要求表的相对位置相同即可,也就是说我们不能根据每个表头指向的数字来进行判断。我们用每个表头之间的差值。因为相对位置相同的表,它的每个表头之间的差值一定是一样的。对于当前表,我们先排好序,这样找差值才是正确的。我们计算出所有的差值。把差值放到一个数组当中。这时我们要利用最小表示法,找到一个出发点坐标,从这个坐标的数开始的字符串是最短的。我们这样规定,哈希会更准确的。找到出发点之后s=11000*s+val[i]。这样得到一个s,这个s就代表了这个差值集合。  询问mp【s】,看看之前是否有相同的,ans+=mp【s】。之后mp【s】+1. 
询问完所有的表之后输出ans即可。

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<string.h>
using namespace std;
int n,m,p;
int a[1100][1100];
int b[1100][1100];
map<long long ,int>mp;


int getmin(int *s)
{
    int i = 0, j = 1, k = 0;
    while(i<m && j<m && k<m)
    {
        int t = s[(i+k)%m]-s[(j+k)%m];
        if (!t) k++;
        else
        {
            if (t>0) i += k+1;
            else j += k+1;
            if (i==j) j++;
            k = 0;
        }
    }
    return i<j?i:j;
}
int main()
{
    cin>>n>>m>>p;
    int ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>a[i][j];
        }
        sort(a[i],a[i]+m);
        a[i][m]=a[i][0]+p;
        for(int j=0;j<m;j++)
        {
            b[i][j]=a[i][j+1]-a[i][j];
        }
        int chufadian=getmin(b[i]);
        int t;
        int s=1;
        for(int j=0;j<m;j++)
        {
             t=(j+chufadian)%m;
             s=s*14000+b[i][t];
        }
        ans+=mp[s];
        mp[s]++;
    }
    cout<<ans<<endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值