2018牛客网暑期ACM多校训练营(第四场) A - Ternary String - [欧拉降幂公式][扩展欧拉定理]

时间:2023-03-03 11:20:56

题目链接:https://www.nowcoder.com/acm/contest/142/A

题目描述

A ternary string is a sequence of digits, where each digit is either 0, 1, or 2.
Chiaki has a ternary string s which can self-reproduce. Every second, a digit 0 is inserted after every 1 in the string, and then a digit 1 is inserted after every 2 in the string, and finally the first character will disappear.
For example, "212'' will become "11021'' after one second, and become "01002110'' after another second.
Chiaki would like to know the number of seconds needed until the string become an empty string. As the answer could be very large, she only needs the answer modulo (109 + 7).

输入描述:

There are multiple test cases. The first line of input is an integer T indicates the number of test cases. 
For each test case: The first line contains a ternary string s (1 ≤ |s| ≤ 10^5).
It is guaranteed that the sum of all |s| does not exceed 2 x 10^6.

输出描述:

For each test case, output an integer denoting the answer. If the string never becomes empty, output -1 instead.

输入

3
000
012
22

输出

3
93
45

题意:

有一串数字串s,只包含三个数字0,1,2,

每过一分钟,先是每个2后面会产生一个1,每个1后面会产生一个0,然后串头第一个数字会消失,

问经过多少秒,整个串全部消失。

题解:

显然,1和2最后都会被消失掉,而0产生不了新的数字,整个串必然在若干秒后会消失,所以不可能有答案为 -1 的可能性;

那么,我们对于串上的每个数字 str[i] 考虑两个时间点 $t$ 和 $t'$,

分别代表:以最开始为 $0$ 秒记,第 $t$ 秒结束时,s[i]成为串头;s[i]成为串头后,在第 $t'$ 秒结时,它以及由它所产生(直接或间接)的所有数字全部消失。

那么,对于三个数字就有三种对应情况:

  1. 数字0:$t' = t + 1$,不管经过多少秒,0都不会再产生任何数字,所以只需要1秒钟就能消除掉;
  2. 数字1:$t' = 2t + 2$,经过 $t$ 秒后,总共产生 $t$ 个0,在 $t+1$ 秒时,又产生一个0,同时1消失,则还剩下 $t+1$ 个0,所以总共花费 $1+t+1$ 秒消除掉全部;
  3. 数字2:$t' = 6 \times 2^t - 3$,不难知道在第 $t+1$ 秒结束时,2产生了这样的数字串:$1101001000 \cdots 1\overbrace {00 \cdots 0}^t$,我们尝试 $t = 0,1,2,3$,就能得到 $t' = 3,9,21,45 \cdots = 1 \times 3,3 \times 3,7 \times 3,15 \times 3 \cdots = \left( {2^{t + 1} - 1} \right) \times 3 = 6 \times 2^t - 3$。

这样一来,假设就可以在 $O\left( {\left| s \right|} \right)$ 时间内计算出消除整个串的时间,

但是这里遇到一个问题,由于模运算的运算规则只有(参见模运算_百度百科):

  1、( a + b ) % n = ( a%n + b%n ) % n

  2、( a - b ) % n = ( a%n - b%n ) % n

  3、( a * b ) % n = ( a%n * b%n ) % n

  4、( a ^ b ) % n = ( (a%n) ^ b ) % n

也就是说,模1e9+7只能在计算 $t' = t + 1$ 和 $t' = 2t + 2$ 的过程直接取模,但是 $t' = 6 \times 2^t - 3$ 里 $t$ 太大了,需要进行降幂,

使用欧拉降幂公式:当且仅当 $B > \phi \left( C \right)$ 时,有 $A^B \bmod C = A^{B\bmod \phi \left( C \right) + \phi \left( C \right)} \bmod C$。(扩展欧拉定理,具体见传送门:https://blog.csdn.net/wu_tongtong/article/details/79631285

其中的 ${\phi \left( n \right)}$ 代表欧拉函数,指不超过 $n$ 且和 $n$ 互质的正整数个数,其中 $n$ 为正整数。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD=1e9+;
const int maxn=1e5+; char s[maxn];
map<ll,ll> mp; ll phi(ll n) //欧拉函数
{
ll res=n;
for(ll i=;i*i<=n;i++)
{
if(n%i==)
{
res=res-res/i;
while(n%i==) n/=i;
}
}
if(n>) res=res-res/n;
return res;
} ll fpow(ll a,ll b,ll p) //快速幂
{
ll r=,base=a%p;
while(b){
if(b&) r*=base, r%=p;
base*=base;
base%=p;
b>>=;
}
return r;
} void init()
{
ll x=MOD;
while(x>) x=(mp[x]=phi(x));
mp[]=;
} ll solve(int i,ll p)
{
if(i==-) return ;
if(p==) return ;
if(s[i]=='') return (*fpow(,solve(i-,mp[p]),p)-+p)%p;
if(s[i]=='') return (*solve(i-,p)++p)%p;
if(s[i]=='') return (solve(i-,p)++p)%p;
return ;
} int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",s);
int len=strlen(s);
printf("%lld\n",solve(len-,MOD));
}
}