牛客网暑期ACM多校训练营(第四场)A - Ternary String 欧拉降幂

比赛的时候推出来的2的公式很麻烦。。结果根本就没想到欧拉降幂
之后看到题解里的公式竟然这么短。。
假设删去之前某个字符存在了n秒
那么删去0的时间 = 1
删去1 = n + 2
删去2 = 3 2 n + 1 n 3
肯定是从左到右推,那么推到某个2的时候,前面的总时间在指数n+1中,因为最终时间是要模1e9+7的,也可以当做 ( 3 2 n + 1 n 3 ) % m o d 根据欧拉降幂公式,可以写成 ( 3 2 ( n + 1 ) % ϕ ( m o d ) + ϕ ( m o d ) n 3 ) % m o d 。所以对这个2之前的数字来说,他们的模数是 ϕ ( 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;
}

猜你喜欢

转载自blog.csdn.net/z631681297/article/details/81264939