51Nod 1282 时钟 —— 最小表示法 + 字符串哈希

题目链接:https://vjudge.net/problem/51Nod-1282


题目来源:  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




题解:

1.对于每个时钟,计算所有相邻时针的间隔,然后用最小表示法表示。

2.借助字符串哈希,将每个经过最小表示法处理后的时钟压缩成一个unsigne long long类型的数。

3.使用map维护。




代码如下:

#include <bits/stdc++.h>
#define rep(i,a,n) for(int (i) = a; (i)<=(n); (i)++)
#define ms(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+7;
const int maxn = 500+10;

int a[maxn][maxn];
int n,m,p;
map<unsigned long long, int >mp;
const unsigned long long seed = 13331;

int getmin(int *s, int len) //返回最小表示法的始端
{
    int i = 0, j = 1, k = 0;
    while(i<len && j<len && k<len)
    {
        int t = s[(i+k)%len]-s[(j+k)%len];
        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()
{
    int ans = 0;
    cin>>n>>m>>p;
    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++)    //获得间隔距离
            a[i][j] = a[i][j+1]-a[i][j];

        int k = getmin(a[i], m);    //k为始端
        unsigned long long s = 1;
        for(int j = 0; j<m; j++)
        {
            int t = (j+k)%m;
            s = 1LL*s*seed + 1LL*a[i][t];   //字符串哈希,seed相当于进制
        }
        ans += mp[s];   //统计对数
        mp[s]++;    //加入到map中
    }
    cout<<ans<<endl;
}





一开始没有用字符串哈希,直接把数组用队列的形式丢进map中,也不会超内存。

#include <bits/stdc++.h>
#define rep(i,a,n) for(int (i) = a; (i)<=(n); (i)++)
#define ms(a,b) memset((a),(b),sizeof((a)))
using namespace std;
typedef long long LL;
const int INF = 2e9;
const LL LNF = 9e18;
const int mod = 1e9+7;
const int maxn = 500+10;

int a[maxn][maxn];
int n,m,p;
map< queue<int>, int >mp;   //把数组以队列的形式丢进map中

int getmin(int *s, int len)
{
    int i = 0, j = 1, k = 0;
    while(i<len && j<len && k<len)
    {
        int t = s[(i+k)%len]-s[(j+k)%len];
        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()
{
    int ans = 0;
    cin>>n>>m>>p;
    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++)
            a[i][j] = a[i][j+1]-a[i][j];

        int k = getmin(a[i], m);
        queue<int>v;
        for(int j = 0; j<m; j++)
        {
            int t = (j+k)%m;
            v.push(a[i][t]);
        }
        ans += mp[v];
        mp[v]++;
    }
    cout<<ans<<endl;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值