zoukankan      html  css  js  c++  java
  • 2018牛客暑假多校四 A(打表+数论)

    题目描述:

        给个长度为n的三进制串,有这样一个操作:在每个2后⾯面插入一个1,每个1后面插 入一个0,然后删掉第一个字符。问多少次操作后,变成空串 n <= 1e5。

    题目分析:

        比赛的时候一直不知道要怎么做,直到赛后才知道这题是个打表题然后用数论的知识进行解决。(emmmm,原本表就打不出来了,结果还加个数论emmmmm)于是我们就来学习一下这题的做法。

        首先我们要发现(愉快的打表过程开始了),在删除字符串的过程中,如果遇到0,直接删除,操作次数+1。而如果遇到1,假设我们之前操作了x次,那么这个1后面就多产生了x个0。因此,此时我们需要再经过x+2次操作才能删完所有字符。而当遇到2,考虑之前已经操作了了x次,然后打(oe)个(is)表可以发现,之后还需要经过次操作才能全部删完 。

        但是,直接快速幂取模或者用矩阵快速幂去处理上述的式子是不可行的,因为x可能相当的大,这就使得如果使用快速幂之类的求幂算法必定会超时。因此我们需要考虑数论中的一种降幂公式。具体看下图:

        有了这条公式,我们就可以进行运算了。但是这里还有一个问题,我们要计算,于是也得计算,同理也还得继续求出,依次类推。因此我们可以优先预处理出来1到1e5的模数的欧拉函数,之后如果遇到字符‘2’则直接调用即可。

    代码:

    #include <bits/stdc++.h>
    #define maxn 100010
    using namespace std;
    typedef long long ll;
    ll powmod(ll a,ll n,ll mo){//快速幂
        ll res=1;
        while(n){
            if(n&1){
                res=res*a%mo;
            }
            n>>=1;
            a=a*a%mo;
        }
        return res;
    }
    ll eular(ll n){//欧拉函数
        ll res=n;
        for(ll i=2;i*i<=n;i++){
            if(n%i==0){
                res-=res/i;
                while(n%i==0){
                    n/=i;
                }
            }
        }
        if(n>1) res-=res/n;
        return res;
    }
    ll mod[maxn];//模数
    void init(){//预处理模数
        mod[0]=1e9+7;
        for(int i=1;i<=1e5+5;i++){
            mod[i]=eular(mod[i-1]);
        }
    }
    char str[maxn];
    int main()
    {
        int t;
        scanf("%d",&t);
        init();
        while(t--){
            scanf("%s",str);
            int cnt=0;
            ll ans=0;
            for(int i=0;str[i]!=0;i++){
                if(str[i]=='2') cnt++;//有几个2就有多少个模数调用
            }
            for(int i=0;str[i]!=0;i++){
                if(str[i]=='0'){
                    ans++;
                    ans%=mod[cnt];
                }
                else if(str[i]=='1'){
                    ans=(ans+ans+2)%mod[cnt];
                }
                else{
                    cnt--;
                    ans=3ll*(powmod(2ll,(ans+1)%mod[cnt],mod[cnt])-1+mod[cnt])%mod[cnt];
                }
            }
            cout<<ans<<endl;
        }
    }
    
  • 相关阅读:
    【4N魔方阵】
    【2(2N+1)魔方阵 】
    【二分查找法(折半查找法)】
    【循环搜寻法(使用卫兵)】
    【合并排序法】
    【快速排序法一】
    【快速排序二】
    【快速排序三】
    【数据结构】之 线性表详解
    【计算机网络基础】
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007255.html
Copyright © 2011-2022 走看看