牛客网暑期ACM多校训练营(第四场):A Ternary String

题意:给出一段数列 s,只包含 0、1、2 三种数。

           每秒:

            在每个 2 后面会插入一个 1 ,

            在每个 1 后面会插入一个 0,

            之后第一个数字消失。

           求最后为空串需要多少秒。

思路:

  先放上结论:

(1)如果在消除一个 0 前经过了 n 秒,那么消掉这个 0 需要 n + 1 秒。

(2)如果在消除一个 1 前经过了 n 秒,那么消掉这个 1 与其产生的所有数需要 (n + 1) * 2 秒。

(3)如果在消除一个 2 前经过了 n 秒,那么消掉这个 2 与其产生的所有数需要 (2 ^ (n + 1) - 1) * 3 秒。

这结论一开始我是不懂的,发现大佬们都这么写,大概是我太菜了,自己推一边吧。//原来是通过暴力打表得出的??? 想推一边的我放弃了。

  //打表代码

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    string s,h;
    long long num;
    while(cin>>s)
    {
        num=0;
        while(!s.empty())
        {
            h="";
            for(int i=0;i<s.length();i++)
            {
                h=h+s[i];
              ///  cout<<h<<"h"<<endl;
                if(s[i]=='2')
                {
                    h=h+'1';
                }
                else if(s[i]=='1')
                {
                    h=h+'0';
                }
            }
            h=h.substr(1,h.length());
            s=h;
            cout<<s<<endl;
            num++;
        }
        cout<<num<<endl;
    }
}

通过暴力打表即可得上述规律,于是再进行下一步。

由于计算量太大,需要用到取模运算,对于0和1公式都只存在加和乘运算,对结果产生不了影响,可是对于2的时候存在求2^{t+1}的运算,然后以该结果作为后面运算的t来运算,模运算的结果发生了变化,若是不会发生变化,都知道是用快速幂来计算,可是为了消除幂运算后产生的变化,我们需要通过计算mod的欧拉值phi,计算了几次就需要取几次mod的欧拉值,即phi(phi(mod))...

欧拉公式:当gcd(a,b)=1时,a^{\phi (b)}=1 (mod b).

当a=2时候,进行推广:
b=x*2^{y},a=2^{k+y}

当k>=0时:

2^{k+y}\equiv 2^{(kmod\phi (x))+y}(mod x*2^y)

emmm,敲这个公式累死了

对k进行操作,取模

可以先处理前面小的那一部分,后面的直接进行递归求解

//膜一下大佬代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
int T,ps[N],x[N],y[N],px[N],pt[N];
char s[N];
int Pow(int x,int y,int mod){
    int ans=1;
    for (;y;y>>=1,x=1LL*x*x%mod)
        if (y&1)
            ans=1LL*ans*x%mod;
    return ans;
}
int phi(int x){
    int ans=x;
    for (int i=2;i*i<=x;i++){
        if (x%i==0){
            ans=ans/i*(i-1);
            while (x%i==0)
                x/=i;
        }
    }
    if (x>1)
        ans=ans/x*(x-1);
    return ans;
}
int solve(int j,int k){
    if (j==0||pt[j]>0)
        return pt[j];
    int i=j;
    while (i>0&&s[i]!='2')
        i--;
    int t=i==0?0:((6LL*Pow(2,solve(i-1,k+1),x[k])-3)%x[k]);
    for (int p=i+1;p<=j;p++){
        if (s[p]=='0')
            t=(t+1)%x[k];
        if (s[p]=='1')
            t=(2*t+2)%x[k];
    }
    t=((t-y[k])%x[k]+x[k])%x[k];
    return t+y[k];
}
int main(){
    ps[0]=1e9+7;
    for (int i=1;i<=100000;i++)
        ps[i]=phi(ps[i-1]);
    for (int i=1;i<=100000;i++){
        for (x[i]=ps[i-1],y[i]=0;x[i]%2==0;x[i]>>=1,y[i]++);
        x[i]=phi(x[i]);
    }
    x[0]=ps[0],y[0]=0;
    scanf("%d",&T);
    while (T--){
        scanf("%s",s+1);
        int n=strlen(s+1),i=0;
        for (int x=0;i<n;i++,pt[i]=x){
            if (s[i+1]=='0')
                x++;
            if (s[i+1]=='1')
                x=x*2+2;
            if (s[i+1]=='2')
                x=6*Pow(2,x,1e9+7)-3;
            if (x>=21)
                break;
        }
        printf("%d\n",(solve(n,0))%ps[0]);
        for (;i>0;i--)
            pt[i]=0;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37748451/article/details/81267982