CSAcademy Prefix Suffix Counting 题解

CSAcademy Prefix Suffix Counting 题解

The meaning of problems

Give you two numbers \ (N \) and \ (M \) , now \ (K \) represent (M \) \ digits. Ask you from \ (1 \) to \ (N \) , the number of digits meet \ (M \) at the same time its former \ (K \) numbers and the \ (K \) digits.

Thinking

We now assume \ (N \) and \ (M \) are strings, if not specifically mentioned, are treated as strings.

Suppose a digital \ (S \) greater than or equal \ (1 \) or less \ (N \) , we discuss its condition can be classified :( same \ (S \) as strings)

  1. \ (S \) greater than the length equal to \ (2K \) , then the prefix and suffix not affect each other, Motian part of the intermediate space in the figure is a value that satisfies less \ (N \) in the case of just fill .
  2. \ (S \) length is less than \ (2K \) , then the prefix and suffix overlap each other, you need to ensure that they do not conflict with each other, which is still to meet before the suffix is \ (M \) . And, you do not have digital free to go fill up.

practice

In the case mentioned above, may be implemented separately:

  1. We enumerate the string length of the current / number, if its total length is less than \ (N \) overall length, it must be smaller than \ (N \) , when the intermediate space can easily fill. If its total length is equal to (N \) \ lengths, then we enumerate a bit in this one before, all the numbers are and \ (N \) is the same, which is a digital than \ ( N \) of this one small, then just fill the back. In particular, it is possible that a previous \ (K \) appears numbers in the past, so in the middle of all the digits are easily filled, or the middle of all the digits are filled \ (0 \) , the current figure is still more than \ (N \) big, then there is no legitimate program.
  2. Similarly, the enumeration current string length / number of overlapping portions satisfy the prefix and suffix of the same conditions require rapid determination, may be used Zor KMPother fast method for string matching.

program

With practice , before using Z matching suffix.

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mod=1000000007;

char s[1000005];//s表示题目中的数字N
char t[1000005];//t表示题目中的数字M
int n,m;//n, m分别表示题目中的N, M的长度
ll pw[1000005],ans;//pw[i]表示10的i次方对mod取模后的大小,ans表示最终答案

bool check(int emp){//check表示中间空出了emp个填0的数位的时候,前后缀是M的数字是否小于等于N,emp<0时,表示前后缀的M重叠了几个位置
    char *r=new char[n+1];
    memset(r,'0',n+1);
    memcpy(r+1+n-(m+emp+m),t+1,m);
    memcpy(r+1+n-m,t+1,m);//构造一个前后缀为M的数字,长度小于N时高位补零
    bool fl=false,va=true;
    for(int i=1;i<=n;i++){
        if(r[i]<s[i])fl=true;
        if(r[i]>s[i]&&!fl)va=false;
    }//判断大小关系(数学意义)
    delete[] r;
    return va;
}

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    pw[0]=1;
    for(int i=1;i<=1000000;i++)pw[i]=pw[i-1]*10%mod;//预处理
    cin>>s+1;
    n=strlen(s+1);
    cin>>t+1;
    m=strlen(t+1);
    if(check(-m))ans++;//单个M作为数字,这里其实可能会出锅,但数据中没有
    int *z=new int[m+1],l=1,r=1;
    z[1]=m;
    for(int i=2;i<=m;i++){
        z[i]=0;
        if(i>r){
            l=i;r=i-1;
            while(r<m&&t[r+1]==t[z[i]+1])r++,z[i]++;
        }else{
            if(i+z[i-l+1]<=r){
                z[i]=z[i-l+1];
            }else{
                l=i;
                z[i]=r-i+1;
                while(r<m&&t[r+1]==t[z[i]+1])r++,z[i]++;
            }
        }
        if(i+z[i]-1==m){
            if(m+m-z[i]<n||(m+m-z[i]==n&&check(-z[i])))ans++;
        }
    }
    delete[] z;//Z算法
    if(m+m<n||(m+m==n&&check(0)))ans++;//计算有数字形如M+M时是否合法
    for(int i=1;m+i+m<n;i++){//枚举空出了i个数字时
        ans=(ans+pw[i])%mod;
    }
    if(m+m<n&&check(n-m-m)){
        int emp=n-m-m;
        bool pref=false,suff=true,suf=false;//pref表示前K个数字是否已经比N小了,这样可以随便填,suff表示M是否小于等于N的K个数字,是就可以让中间的数字全部等于N对应数位
        for(int i=1;i<=m;i++){
            if(s[i]>t[i])pref=true;
            if(s[i+n-m]>t[i])suf=true;
            if(s[i+n-m]<t[i]&&!suf)suff=false;
        }
        if(pref)ans=(ans+pw[emp])%mod;//加上中间任意填的方案
        else{
            ans=(ans+suff)%mod;//加上suff的方案
            for(int i=m+1;i<=n-m;i++){
                ans=(ans+pw[n-m-i]*(s[i]-'0'))%mod;//加上当前位前面的数字和N相同,当前位小于N对应数位,后面随便填的方案
            }
        }
    }
    cout<<ans%mod<<endl;

    return 0;
}

Guess you like

Origin www.cnblogs.com/BlahDuckling747/p/12581930.html