NowCoder2018多校A Ternary String 拓展欧拉定理

NowCoder2018多校A Ternary String 拓展欧拉定理

题意

给定带前导0的三进制数,每秒自动进行一次操作,1的后面多一个0,2的后面多一个1,开头的字符被删除,求这个数变为空的操作次数

求操作次数取模\(1e9+7\)

\[1 \leq |s| \leq 10^5 \]

分析

考虑记录时间,原串中每个数带来的贡献,可以简单归纳得出

0:\(t + 1\)

1:\(2(t + 1)\)

2:\(3(2^{t + 1} - 1)\)

操作12都可以轻松得到结果,对于3,计算\(2^{t + 1} \ mod \ MOD\)是不方便的,考虑使用拓展欧拉定理

\[a^b \equiv \begin{cases} a^{b \bmod \varphi(m)},gcd(a,m) = 1\\ a^b ,gcd(a,m) \neq 1,b \leq \varphi(m) (mod \ m)\\ a^{b \ mod \varphi(m) +\varphi(m)},gcd(a,m) \neq 1,b \geq \varphi(m) \end{cases} \]

使用时,要求幂对\(\varphi(m)\)取模,因此我们记录\(t\)时还需额外记录\(\varphi(m)\)意义下的\(t\),维护\(\varphi(m)\) 意义下的\(t\)又需要嵌套上模\(\varphi(\varphi(m))\)

为了方便实现,可以采用DFS的方式记录当前第几个数和当前的模数,至于为什么不用判断\(b \geq \varphi(m)\),我也不是很懂

代码

const int MOD = (int)1e9 + 7;

int m[35],ans[35];


inline int mul(int a,int b,int i){
    return (ll)a * b % i;
}


inline  void add(int &a,int b,int i){
    a += b;
    if(a >= i) a -= i;
}

inline int ksm(int a,ll b = MOD - 2,int m = MOD){
    int ans = 1;
    int base = a;
    while(b){
        if(b & 1) {
            ans = (ll)ans * base % m;
        }
        base = (ll)base * base % m;
        b >>= 1;
    }
    return ans;
}


inline int get_phi(int n) {
    int m = int(sqrt(n + 0.5));
    int ans = n;
    for (int i = 2; i <= m; i++) {
        if (n % i == 0) {
            ans = ans / i * (i - 1);
            while (n % i == 0) n /= i;
        }
    }
    if (n > 1) ans = ans / n * (n - 1);
    return ans;
}

unordered_map<int,int> mp;
char s[100005];

int dfs(int len,int m){
    if(!len) return 0;
    if(s[len] == '0')
        return (dfs(len - 1,m) + 1) % m;
    if(s[len] == '1') 
        return (ll)2 * (dfs(len - 1,m) + 1) % m;
    //if(mp[m] != 1) return (mul(3,ksm(2,(dfs(len - 1,mp[m]) + 1) % mp[m],m),m) + m - 3) % m;
    int p = dfs(len - 1,mp[m]) + 1;
    if(m != 1 && m != MOD) {
        if(p >= mp[m]) return (mul(3,ksm(2,p % mp[m] + mp[m],m),m) + m - 3) % m;
        else return (mul(3,ksm(2,p % mp[m],m),m) + m - 3) % m;
    }  
    return (mul(3,ksm(2,p % mp[m],m),m) + m - 3) % m;
}

int main(){
    int T = rd();
    int tmp = MOD;
    mp[1] = 1;
    while(tmp > 1) {
        mp[tmp] = get_phi(tmp);
        tmp = mp[tmp];
    }
    while(T--){
       scanf("%s",s + 1);
       int len = strlen(s + 1);
       printf("%d\n",dfs(len,MOD));
    }
}
上一篇:【题解】函数


下一篇:多元函数微分学条件极值(拉格朗日乘数法)求解技巧总结