[luogu SP4354][poj 3349]Snowflake Snow Snowflakes{哈希+最小表示法(最小同构串)}

题目

http://poj.org/problem?id=3349

https://www.luogu.org/problemnew/show/SP4354


解题思路

本题我调了很久!!!
这道题的 u s s i g n e d   ( l o n g   l o n g ) ussigned\ (long\ long) ussigned (long long)很烦,不过它们有自然溢出的功能。
因为顺时针和逆时针都可以,所以只需将原串在前后复制两遍,然后做两遍最小表示法,求出最小同构串, h a s h hash hash一下即可。


代码

#include<cstdio>
#include<algorithm>
using namespace std; 
const unsigned inf=160001; 
unsigned long long h[inf];
unsigned a[21],n; 
unsigned in(){
    unsigned ans=0; char c=getchar();
    while (c<48||c>57) c=getchar();
    while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
    return ans;
}
int findd(unsigned long long k)//hash哈希表
{
    unsigned g=k%inf,i=0; 
    while (i<inf&&h[(g+i)%inf]&&h[(g+i)%inf]!=k) i++; 
    return (g+i)%inf; 
}
bool hash(unsigned ans1,unsigned ans2)
{
    bool b=0; unsigned i,summ,ans=ans1; unsigned long long sum=0;  
    for (i=0;i<6&&a[ans1+i]==a[ans2-i];i++);//求最小同构串
    if (a[ans1+i]>a[ans2-i]) {ans=ans2; b=1;}
    if (b) {//累求hash值
        for (unsigned j=ans;j>ans-6;j--) 
          sum=sum*13131+a[j]; 
    } else {
        for (unsigned j=ans;j<ans+6;j++) 
          sum=sum*13131+a[j]; 
    }
    if (h[(summ=findd(sum))]==sum) return 1; 
    h[summ]=sum; return 0; 
}
int main()
{
    n=in(); 
    while (n--)
    {
        for (unsigned i=7;i<=12;i++) 
          scanf("%d",&a[i]),a[i-6]=a[i+6]=a[i]; 
        int ii=7,jj=8,kk; 
        while (ii<=12&&jj<=12)//顺时针
        {
            kk=0; while (kk<=6&&a[ii+kk]==a[jj+kk])kk++; 
            if (kk==6) break; 
            if (a[ii+kk]>a[jj+kk]) {ii=ii+kk+1; if (ii==jj) ii++;} 
            else {jj=jj+kk+1; if (ii==jj) jj++;}
        }
        unsigned ans1=min(ii,jj); ii=12,jj=11;
        while (ii>=7&&jj>=7)//逆时针
        {
            kk=0; while (kk<=6&&a[ii-kk]==a[jj-kk])kk++; 
            if (kk==6) break; 
            if (a[ii-kk]>a[jj-kk]) {ii=ii-kk-1; if (ii==jj) ii--;} 
            else {jj=jj-kk-1; if (ii==jj) jj--;}
        }
        unsigned ans2=max(ii,jj); 
        if (hash(ans1,ans2)) {
           printf("Twin snowflakes found."); return 0; 
        } 
    }
    printf("No two snowflakes are alike."); 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值