牛客多校第四场 A-Ternary String(欧拉降幂)

127 篇文章 0 订阅
85 篇文章 2 订阅

Ternary String

问题分析

题意:问多长时间后可以将整个序列完全消除,每秒序列会在 1 1 后面插入一个0,在 2 2 后面插入一个1,作为序列的第一个数字将会消失。最后答案对 1e9+7 1 e 9 + 7 取模。
emmm,通过打表就可以发现
假设现有一个长度为 n n 的序列,
每次序列插入一个0后,我们需要 n+1 n + 1 秒才能将这个序列消除;
每次序列插入一个 1 1 后,我们需要2n+1秒才能将这个序列消除;
每次序列插入一个 2 2 后,我们需要3(2n+11)秒才能将这个序列消除。

再来看一下数据范围, n n 最大有2e6,明显在处理 3(2n+11) 3 ⋅ ( 2 n + 1 − 1 ) 的时候会超时。所以此时欧拉降幂就能很好的优化这种算式了。详情请看蒻刚补的欧拉定理叭。然后如果泥萌看了我的那篇欧拉定理的话,就会发现如果我们从 φ(1e9+7) φ ( 1 e 9 + 7 ) 不断嵌套求 φ φ 值,每次模数除了第一次都是偶数,最后我们一定可以在不多于 log2(p) l o g 2 ( p ) 次内将 φ φ 值降为 1 1 ,所以可以采用递归回溯计算。

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

但是这里为了方便理解,窝就贴一个非递归的代码。。因为是多组数据,因此我们需要预处理出 φ(φ(φ(...φ(1e9+7)))) φ ( φ ( φ ( . . . φ ( 1 e 9 + 7 ) ) ) )

#include<bits/stdc++.h>
typedef long long LL;

LL phi(LL n) { 
    LL ret = 1;
    for (LL i = 2; i * i <= n; ++i) {
        if (n % i == 0) {
            n /= i, ret *= i - 1;
            while (n % i == 0)
                n /= i, ret *= i;
        }
    }
    if (n > 1) ret *= n - 1;
    return ret;
}

std::map<LL,LL> m;
char s[100001];

LL pow_(LL a,LL n,LL mod) {
    LL ans = 1;
    while (n) {
        if (n & 1) ans = ans * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return ans;
}

int main() {
    LL T;
    m[0] = 1e9 + 7;
    for (int i = 1; i < 1e5; ++i)
        m[i] = phi(m[i - 1]);
    std::cin >> T;
    while (T--) {
        std::cin >> s;
        int cnt = 0;
        for (int i = 0; s[i]; ++i)
            if (s[i] == '2')
                cnt++;
        LL ans = 0;
        for (int i = 0; s[i]; ++i) {
            if (s[i] == '0')
                ans++, ans %= m[cnt];
            else if (s[i] == '1')
                ans = (ans * 2 + 2) % m[cnt];
            else {
                cnt--;
                if (ans < m[cnt])
                    ans = 3 * (pow_(2, (ans + 1) % m[cnt], m[cnt]) - 1 + m[cnt]) % m[cnt];
                else
                    ans = 3 * (pow_(2, (ans + 1) % m[cnt] + m[cnt], m[cnt]) - 1 + m[cnt]) % m[cnt];
            }

        }
        std::cout << ans << std::endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值