一个字符串只含有'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秒之后需要几秒才能删除该字符。
显然
现在求解F2:
(该串为[2])
(该串为[21])
(该串为[2110])
(该串为[2110100])
......通过观察得出递推式:
左右添项得:
所以 是首项为3+0+3=6,公比为2的等比数列:
所以:
但是递推的时候显然需要计算一个,其中T是处理到该字符的时间
由欧拉函数性质:在对P取模的运算中
计算模P的结果的T时,需要计算模Φ(P)结果得到的T,要得到这个模Φ(P)结果的T又需要计算Φ(Φ(P))结果的T....
需要一直复合欧拉函数进行运算,比如说我们整个串有3个2,那么我们就先以模[1e9+7复合欧拉3次]进行计算答案,递推到第一个2的时候,以这个答案直接代入,就能算出模[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;
}