比赛的时候推出来的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
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;iif ( s[i] == '2' ) cnt++;
for (int i=0;iif (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;
}