Description
给出一个只有 0,1,2 0 , 1 , 2 组成字符串,每一步操作,首先每个 1 1 后面多出一个,每个 2 2 后面多出一个,然后第一个数字消失,问多少次操作后该字符串变成空串,如果该字符串不可能变成空串则输出 −1 − 1
Input
第一行输入一整数 T T 表示用例组数,每组用例输入一个只由组成的字符串 s s
Output
对于每组用例,输出消除字符串 s s 所需要的操作数,结果模,如果该字符串不可能变成空串则输出 −1 − 1
Sample Input
3
000
012
22
Sample Output
3
93
45
Solution
对于
ai
a
i
,假设消除
a1,...,ai−1
a
1
,
.
.
.
,
a
i
−
1
需要
x
x
次操作,记消除及其延伸出的数字需要的操作次数为
Solve(i,x)
S
o
l
v
e
(
i
,
x
)
,简单递推有
记 f(i) f ( i ) 表示消除 a1,...,ai a 1 , . . . , a i 所需的操作数,那么有以下转移
因为每次遇到 2 2 都会将之前的答案放在指数上,由指数循环定理,只要根据当前位后面有几个 2 2 来修改模数即可,例如后面有一个的时候需要模 φ(109+7)=109+6 φ ( 10 9 + 7 ) = 10 9 + 6 ,后面有两个 2 2 的时候需要模,以此类推,注意要开一个标记变量记录之前的答案与当前模数欧拉函数值的大小关系来判断是否需要在幂指数上多加一个欧拉函数值,时间复杂度 O(n) O ( n )
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
#define maxn 100005
int T,mod[30]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,5242880,19660800,79872000,243900800,500000002,1000000006,1000000007};
char s[maxn];
int mul(int x,int y,int c)
{
ll z=1ll*x*y;
return z-z/c*c;
}
int add(int x,int y,int c)
{
x+=y;
if(x>=c)x-=c;
return x;
}
int Pow(int a,int b,int c)
{
int ans=1;
while(b)
{
if(b&1)ans=mul(ans,a,c);
a=mul(a,a,c);
b>>=1;
}
return ans;
}
int euler(int n)
{
int ans=n;
for(int i=2;i*i<=n;i++)
if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0)n/=i;
}
if(n>1)ans=ans/n*(n-1);
return ans;
}
P Solve(int n,int i)
{
if(n==0)return P(0,0);
if(i==0)return P(0,1);
P a;
if(s[n]=='2')a=Solve(n-1,i-1);
else a=Solve(n-1,i);
if(s[n]=='0')
{
a.first++;
return P(a.first%mod[i],a.second||(a.first>=mod[i]?1:0));
}
if(s[n]=='1')
{
a.first=2*a.first+2;
return P(a.first%mod[i],a.second||(a.first>=mod[i]?1:0));
}
if(s[n]=='2')
{
if(a.second)a.first+=mod[i-1];
if(a.first>=30)
{
a.first=mul(3,add(Pow(2,a.first+1,mod[i]),mod[i]-1,mod[i]),mod[i]);
a.second=1;
return a;
}
else
{
ll temp=3ll*((1ll<<(a.first+1))-1);
return P(temp%mod[i],temp>=mod[i]?1:0);
}
}
return P(0,0);
}
int main()
{
int res=29;
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1);
int n=strlen(s+1);
printf("%d\n",Solve(n,res-1).first);
}
return 0;
}