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

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

你可能感兴趣的:(数论)