2018牛客暑期多校第四场A(欧拉降幂)

题目描述:

一个字符串只含有'0','1','2',在每一秒会在每个'1'后生成一个'0',每个'2'后面生成一个'1',并删除第一个字符:

例如:字符串“210”的删除过程

第0秒:210

第1秒:1100

第2秒:01000

第3秒:10000

第5秒:00000

第6秒:0000

。。。第9秒该字符串消失。

要求:输入一个串,长度不超过1e5,问第几秒这个串会消失,答案对1e9+7取模。

题目分析:

现在考虑三个函数F0(t),F1(t),F2(t),分别表示'0' '1' '2'存在了t秒之后需要几秒才能删除该字符。

显然F_0(t)=1, F_1(t)=t+2;

现在求解F2:

{F_{2}}(0) = 3                                                                                   (该串为[2])

F_{2}(1) = F_{2}(0)+F_{1}(F_{2}(0)) = 3 + (3 + 2) = 8                      (该串为[21])

F_{2}(2) = F_{2}(1)+F_{1}(F_{2}(1)) + 1 = 8 + (8 + 2) + 1 = 19      (该串为[2110])

F_{2}(3) = F_{2}(2)+F_{1}(F_{2}(2)) + 2 = 19 + (19 + 2) + 2 = 42  (该串为[2110100])

......通过观察得出递推式:

F_{2}(t) = F_{2}(t-1)+F_{1}(F_{2}(t-1)) + t-1

= F_{2}(t-1)+F_{2}(t-1) + 2 + t-1

= 2*F_{2}(t-1)+t+1

左右添项得:

[F_{2}(t) + t + 3] = 2[F_{2}(t-1)+ (t-1) + 3]

所以 F_{2}(t) + t + 3 是首项为3+0+3=6,公比为2的等比数列:

{F_{2}}(t) + t + 3 = 6*2^t

所以:F_{2}(t)= 3*2^{t+1} - t +3

但是递推的时候显然需要计算一个2^{T},其中T是处理到该字符的时间

由欧拉函数性质:在对P取模的运算中 a^{\Phi \left ( p \right )}\equiv 1 (mod P)

计算模P的结果的T时,需要计算模Φ(P)结果得到的T,要得到这个模Φ(P)结果的T又需要计算Φ(Φ(P))结果的T....

需要一直复合欧拉函数进行运算,比如说我们整个串有3个2,那么我们就先以模[1e9+7复合欧拉3次]进行计算答案,递推到第一个2的时候,以这个答案直接代入F_{2}(t)= 3*2^{t+1} - t +3,就能算出模[1e9+7复合欧拉2次]的答案,递推到第二个2的时候,同样代入式子就能算出模[1e9+7的欧拉函数值]的答案,遇到第三个2的时候,代入式子就能算出模1e9+7的答案了。这个过程逆向求的话就是一个dfs的过程。

代码:

#include 
using namespace std;
typedef long long ll;
map m;

//求x的欧拉函数值
ll PH(ll x){
    ll res=x,a=x;
    for(ll i=2;i*i<=x;i++){
        if(a%i==0){
            res=res/i*(i-1);
            while(a%i==0) a/=i;
        }
    }
    if(a>1) res=res/a*(a-1);
    return res;
}
//模mod快速幂
ll quick_pow(ll a,ll b,ll mod){
    ll ans=1;
    while(b){
        if(b&1) ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
char s[100005];
//求解到字符a[i]的模mod下的答案
ll dfs(ll i,ll mod)
{      //以下注释以ans代表求解至a[i-1]的答案
    if(i==0) return 0;
    else if(s[i]=='0') return (dfs(i-1,mod)+1)%mod;  //ans+1
    else if(s[i]=='2') return (3ll*quick_pow(2,dfs(i-1,m[mod])+1,mod)-3+mod)%mod;
            //3*2^ans+1%φ(mod)-3
    else return (2*dfs(i-1,mod)+2)%mod;     //ans*2+2
}
int main(){
    ll mo=1e9+7;
    //求欧拉函数的复合
    while(mo!=1){
        m[mo]=PH(mo);
        mo=m[mo];
    }
    m[1]=1;//1的欧拉函数值就是1
    int T;
    scanf("%d",&T);
    while(T--){
        cin>>s+1;
        int n=strlen(s+1);
        printf("%lld\n",dfs(n,1000000007));
    }
    return 0;
}

 

你可能感兴趣的:(数论)