【Mail.Ru Cup 2018 Round 3 E. Check Transcription 】Hash+尺取

探讨了一种算法,用于解决01串s通过特定映射转换为另一字符串t的问题,涉及hash技巧与复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


E. Check Transcription

题意

给你一个01串s,一个字符串t,
0可以映射成r0,1可以映射成r10可以映射成r_0,1可以映射成r_10r01r1
问有多少组r0,r1可以满足映射之后s=t问有多少组r_0,r_1可以满足映射之后s=tr0,r1s=t
∣s∣&lt;=105,∣t∣&lt;=106|s|&lt;=10^5,|t|&lt;=10^6s<=105,t<=106

做法

我们设置s串中0的个数为num0,s串中1的个数为num1我们设置s串中0的个数为num_0,s串中1的个数为num_1s0num0,s1num1
如果固定r0的长度,也就固定了r1的长度,也就确定了r0和r1如果固定r_0的长度,也就固定了r_1的长度,也就确定了r_0和r_1r0r1,r0r1
由于num0∗len(r0)+num1∗len(r1)=len(t)由于num_0*len(r_0)+num_1*len(r_1)=len(t)num0len(r0)+num1len(r1)=len(t)
我们只要枚举len(r0)就可以我们只要枚举len(r_0)就可以len(r0)
首先要判断len1是否为整数,之后枚举s串用hash判断每一位0或1是否能正确转义首先要判断len_1是否为整数,之后枚举s串用hash判断每一位0或1是否能正确转义len1shash01
如果每一位都可以转义那么ans++,注意这里hash用自动溢出会被卡,需要多hash如果每一位都可以转义那么ans++,注意这里hash用自动溢出会被卡,需要多hashans++,hashhash
复杂度分析(来自pls)复杂度分析(来自pls)(pls)
枚举0的长度len0,那么就有n/len0个可行解枚举0的长度len0,那么就有n/len0个可行解0len0n/len0
每个可行解要做n次hash每个可行解要做n次hashnhash
对于len0&gt;n/2,总复杂度就是O(n2/len0)≈O(n)对于len0&gt;n/2,总复杂度就是O(n^2/len0) \approx O(n)len0>n/2,O(n2/len0)O(n)
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
typedef unsigned long long ull;
const int maxn = 1e6+10;
char str[maxn],t[maxn];
template <int T>
struct StringHash
{
  std::vector<std::vector<int>> ha, pw;
  std::vector<int> M;

  explicit StringHash(const std::string& s)
      : StringHash(std::vector<int>(s.begin(), s.end())) {}

  explicit StringHash(const std::vector<int>& vec)
  {
    pw = ha =
        std::vector<std::vector<int>>(T, std::vector<int>(vec.size() + 1));
    std::vector<int> C;
    for (int i = 0; i < T; i++)
    {
      pw[i][0] = 1;
      C.push_back(rand_int());
      M.push_back(rand_int());
    }
    for (int z = 0; z < T; z++)
    {
      for (size_t i = 0; i < vec.size(); ++i)
      {
        ha[z][i + 1] = (1LL * ha[z][i] * C[z] + vec[i]) % M[z],
                  pw[z][i + 1] = 1LL * pw[z][i] * C[z] % M[z];
      }
    }
  }

  // hash value of interval [a, b)
  std::vector<int> hash_interval(int a, int b)
  {
    std::vector<int> ret(T);
    for (int z = 0; z < T; z++)
    {
      ret[z] = (ha[z][b] - 1LL * ha[z][a] * pw[z][b - a] % M[z] + M[z]) % M[z];
    }
    return ret;
  }

  static int rand_int() {
    static std::mt19937 gen((std::random_device())());
    static std::uniform_int_distribution<int> uid(1e8, 1e9);
    return uid(gen);
  }
};
int num[2];
int main()
{
    scanf("%s%s",str,t);
    StringHash<10> sh(t);
    int lens=strlen(str);
    int lent=strlen(t);
    int ans=0;
    for(int i=0;i<lens;i++)
    {
        if(str[i]=='0') num[0]++;
        else num[1]++;
    }
    for(int i=1;i*num[1]<lent;i++)
    {
        if(((lent-i*num[1])%num[0])!=0) continue;
        int len0=(lent-i*num[1])/num[0];
        int len1=i;
        vector<int> flag0,flag1;
        int f0=-1,f1=-1;
        int flag=0;
        int tmp=0;
        for(int j=0;j<lens;j++)
        {
            if(str[j]=='0')
            {
               if(f0==-1)
               {
                   f0=1;
                   flag0=sh.hash_interval(tmp,tmp+len0);
                   tmp+=len0;
               }
               else
               {
                    vector<int> tt=sh.hash_interval(tmp,tmp+len0);
                    if(tt!=flag0)
                    {
                        flag=1;
                        break;
                    }
                    else
                    {
                        tmp+=len0;
                    }
               }
            }
            else
            {
               if(f1==-1)
               {
                   f1=1;
                   flag1=sh.hash_interval(tmp,tmp+len1);
                   tmp+=len1;
               }
               else
               {
                    vector<int> tt=sh.hash_interval(tmp,tmp+len1);
                    if(tt!=flag1)
                    {
                        flag=1;
                        break;
                    }
                    else
                    {
                        tmp+=len1;
                    }
               }
            }
        }
        if(flag0!=flag1&&flag==0) ans++;
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值