hdu2609-字符串最小表示法|模拟|二分+lcp-How many

15 篇文章 0 订阅
8 篇文章 0 订阅

http://acm.hdu.edu.cn/showproblem.php?pid=2609
给你m个串,长度相等。只有0和1组成,
他们都可以把后面的 放在前面。并且这种串算作相同的
比如 1100 1001 0011 0110 这四个。
问你m个中有多少不同的。
暴力写的,后来看别人的题解。最小表示法,O(n),,类似用两个指针 来比较,利用的是 字典序的相关特质,
还有一个lcp+二分的,先mark。

#include <bits/stdc++.h>
using namespace std;
/* 或者用 字符串的最小表示法。
  用来解决字符串的同构问题。
  同构即 一个字符串最后面的移动到前面,然后
  形成总共 (长度len)个 串,这些串同构。
*/
const int maxn=2e5;
int  MINR(string s){
    int len=s.length();
    int i=0;int j=1;
    //int k=0;
    while(i<len/2&&j<len/2){
          int k=0;
          while(s[i+k]==s[j+k]&&k<len/2) k++;
           if(k==len/2) return min(i,j);
           if(s[i+k]>s[j+k])// 若求最大,把大于改成小于,下面也是。
              i=max(i+k+1,j+1);
          else if(s[i+k]<s[j+k])
              j=max(j+k+1,i+1);
    }
    return min(i,j);
}
int main()
{    int t;
    string s[maxn];
     vector<string>w;
    while(~scanf("%d",&t)){
          w.clear();
          for(int i=0;i<t;i++){
             cin>>s[i];
             s[i]+=s[i];
          }
          for(int i=0;i<t;i++){
              int r=MINR(s[i]);
              //cout<<r<<endl;
              //cout<<s[i].substr(r,s[i].length()/2)<<endl;
              w.push_back(s[i].substr(r,s[i].length()/2));

          }
          sort(w.begin(),w.end());
          w.erase(unique(w.begin(),w.end()),w.end());
          /*for(int i=0;i<w.size();i++){
             cout<<w[i]<<endl;
          }*/
          printf("%d\n",w.size());
    }
    return 0;
}

暴力。比那个慢点
bitset应该也行,不过得自己写。。

#include <bits/stdc++.h>
using namespace std;
/* bitset模拟。
   srting

*/
const int maxn=1e5;
int main()
{    int n;
      string s[maxn];
     set<string>se;
    while(cin>>n){
          se.clear();
          for(int i=0;i<n;i++){
             cin>>s[i];
             s[i]+=s[i];
             //s[i]+=s[i];
            // cout<<s[i]<<endl;
          }
         // cout<<s[0][0]<<endl;
          vector<string> kk;
          for(int i=0;i<n;i++){
             {   kk.clear();
                for(int j=0;j<s[i].length()/2;j++){
                 //cout<<s[i][j]<<endl;
                 string w=s[i].substr(j,s[i].length()/2);
                 //cout<<w<<endl;
                   kk.push_back(w);
                 }
                 sort(kk.begin(),kk.end());
                 //cout<<kk[0]<<endl;
                  se.insert(kk[0]);
             }
          }
          //set<string>::iterator it;
          //for(it=se.begin();it!=se.end();it++)
           // cout<<*it<<endl;
          printf("%d\n",se.size());



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值