比赛的时候推出来的2的公式很麻烦。。结果根本就没想到欧拉降幂
之后看到题解里的公式竟然这么短。。
假设删去之前某个字符存在了n秒
那么删去0的时间 = 1
删去1 = n + 2
删去2 =
3∗2n+1−n−3
3
∗
2
n
+
1
−
n
−
3
肯定是从左到右推,那么推到某个2的时候,前面的总时间在指数n+1中,因为最终时间是要模1e9+7的,也可以当做
(3∗2n+1−n−3)%mod
(
3
∗
2
n
+
1
−
n
−
3
)
%
m
o
d
根据欧拉降幂公式,可以写成
(3∗2(n+1)%ϕ(mod)+ϕ(mod)−n−3)%mod
(
3
∗
2
(
n
+
1
)
%
ϕ
(
m
o
d
)
+
ϕ
(
m
o
d
)
−
n
−
3
)
%
m
o
d
。所以对这个2之前的数字来说,他们的模数是
ϕ(mod)
ϕ
(
m
o
d
)
,所以要统计一下2的个数,倒着退回去,注意大于28的时候只有1了,所以数组写到这里就可以了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5+100;
char s[MAXN];
ll ans;
int cnt;
ll mod[]={1000000007,1000000006,500000002,243900800,79872000,19660800,5242880,2097152,1048576,524288,262144,131072,65536,32768,16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1};
ll euler(ll n)
{
ll ans = n;
for (int i=2;i*i<=n;i++)
{
if (n % i == 0)
{
ans-= ans/i;
while (n%i == 0) n/=i;
}
}
if (n>1) ans -= ans/n;
return ans;
}
ll qpow(ll a,ll k,ll m)
{
ll ans=1,tmp=a;
while (k)
{
if (k&1) ans = ans * tmp % m;
k>>=1;
tmp = tmp * tmp %m;
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
while (n--)
{
scanf("%s",s);
ans = cnt = 0;
ll tot = 0;
int len = strlen(s);
for (int i=0;i<len;i++) if ( s[i] == '2' ) cnt++;
for (int i=0;i<len;i++)
{
if (s[i] == '0') tot = (tot+1)% mod[min(28,cnt)];
if (s[i] == '1') tot = (tot + tot + 2)% mod[min(28,cnt)];
if (s[i] == '2')
{
ll modtmp = mod[min(28,cnt-1)];
tot = ( tot + 3*qpow(2,tot+1,modtmp) - tot - 3 )%modtmp + modtmp;
cnt--;
}
}
printf("%lld\n",tot%mod[0]);
}
return 0;
}