Description
给出一个只有0,1,20,1,2组成字符串,每一步操作,首先每个11后面多出一个,每个22后面多出一个,然后第一个数字消失,问多少次操作后该字符串变成空串,如果该字符串不可能变成空串则输出−1−1
Input
第一行输入一整数TT表示用例组数,每组用例输入一个只由组成的字符串ss
Output
对于每组用例,输出消除字符串ss所需要的操作数,结果模,如果该字符串不可能变成空串则输出−1−1
Sample Input
3
000
012
22
Sample Output
3
93
45
Solution
对于aiai,假设消除a1,...,ai−1a1,...,ai−1需要xx次操作,记消除及其延伸出的数字需要的操作次数为Solve(i,x)Solve(i,x),简单递推有
Solve(i,x)=⎧⎩⎨⎪⎪1x+23⋅2x+1−x−3ai=0ai=1ai=2Solve(i,x)={1ai=0x+2ai=13⋅2x+1−x−3ai=2
记f(i)f(i)表示消除a1,...,aia1,...,ai所需的操作数,那么有以下转移
f(i)=⎧⎩⎨⎪⎪f(i−1)+12⋅(f(i−1)+1)3⋅(2f(i−1)+1−1)ai=0ai=1ai=2f(i)={f(i−1)+1ai=02⋅(f(i−1)+1)ai=13⋅(2f(i−1)+1−1)ai=2
因为每次遇到22都会将之前的答案放在指数上,由指数循环定理,只要根据当前位后面有几个22来修改模数即可,例如后面有一个的时候需要模φ(109+7)=109+6φ(109+7)=109+6,后面有两个22的时候需要模,以此类推,注意要开一个标记变量记录之前的答案与当前模数欧拉函数值的大小关系来判断是否需要在幂指数上多加一个欧拉函数值,时间复杂度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;
}