• CodeToN cf #3 Div.1+2 (A-D)


    CodeToN cf #3 Div.1+2

    A. Indirect Sort

    • 题意

      • 给定一个n的排列,问这个排列能否通过下列操作变成单调不递减的数组
      • 操作:从前到后选择三个不同的位置i,j,k,如果ai>ak,那么ai=ai+aj,否则swqp(aj,ak)
    • 题解

      • 思维+贪心。思路来源:一个是ai>ak也可以叠加,另一个是最后的数组需要单调不减,那么就会容易想到最极端的数据1
      • 对于数值1,模拟一下情况,看可以怎样操作。充分
        • 如果i指向1,由于1是最小的ai
        • 那么k指向1的时候,ai>ak恒成立,所以1的位置不变;当j指向1时,1要么不变,要么会向后移动,即移动不到第一个位置
        • 由此得出结论,1不在第一个位置一定不可以,逆否则为只有1在第一个位置可以
      • 证明结论的必要性,如果1在第一个位置,可以让i一直指向1,那么ai
    • 代码

    #include 
    
    using namespace std;
    
    void solve() {
        int n,a[15]; cin>>n;
        for(int i=0;i<n;i++) cin>>a[i];
        if(a[0]==1) cout<<"Yes"<<'\n';
        else cout<<"No"<<'\n';
    }
    
    int main() {
        int t=1; cin>>t;
        while(t--) solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    B. Maximum Substring

    • 题意

      • 给定一个长度为n的01串,对于任意一个子串的价值计算如下
        v a l u e = { c n t 0 × c n t 1 , ( c n t 0 ! = 0 , c n t 1 ! = 0 ) c n t 0 × c n t 0 , ( c n t 0 ! = 0 , c n t 1 = 0 ) c n t 1 × c n t 1 , ( c n t 0 = 0 , c n t 1 ! = 0 ) value= \begin{cases} cnt_0\times cnt_1,&(cnt_0!=0,cnt_1!=0)\\ cnt_0\times cnt_0,&(cnt_0!=0,cnt_1=0)\\ cnt_1\times cnt_1,&(cnt_0=0,cnt_1!=0)\\ \end{cases} value= cnt0×cnt1,cnt0×cnt0,cnt1×cnt1,(cnt0!=0,cnt1!=0)(cnt0!=0,cnt1=0)(cnt0=0,cnt1!=0)

      • 问所有子串价值的最大值为多少

    • 题解

      • 贪心。如果子串选择有0有1的,那么肯定整个字符串是最大值;如果子串只有0或者1时,那么含有最大连续相同字符的子串价值最大。所以只需要比较两种价值哪一种更大
    • 代码

    #include 
    
    using namespace std;
    const int N=1e5+10;
    int a[N];
    
    void solve() {
        int n; long long res=0; cin>>n;
        string s; cin>>s;
        int ma=0,maa=0,cnt1=0,cnt0=0;
        int temp=0;
    
        for(auto i:s) {
            if(i=='1') {
                cnt1++;
                temp++;
                ma=max(ma,temp);
            }
            else {temp=0;cnt0++;}
        }
        temp=0;
        for(auto i:s) {
            if(i=='0') {
                temp++;
                maa=max(maa,temp);
            }
            else temp=0;
        }
        
        if(1ll*ma*ma>1ll*maa*maa) res=1ll*ma*ma;
        else res=1ll*maa*maa;
        if(1ll*cnt0*cnt1>res) res=1ll*cnt0*cnt1;
        cout<<res<<'\n';
    }
    
    int main() {
        int t=1; cin>>t;
        while(t--) solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    C. Complementary XOR

    • 题意

      • 给定两个长度为n的01串a和b,每次选定一个区间[l,r],a[l,r]进行01翻转,b[1,l-1]和b[r+1,n]进行01翻转
      • 问能否使得a和b都变成0,如果能操作的区间应该是哪些
    • 题解

      • 思维+构造。正着模拟实在是有点摸不着头脑,可以逆向模拟一下,如果a和b都是0,那么通过操作可以变成什么样子,就可以说明只有这种样子可以操作变成0
      • 逆向模拟发现:不论区间怎么选,如果进行奇数次操作,那么ai=!bi(对于每个i来说);如果进行偶数次操作,那么ai=bi(对于每个i来说)。因此可以得出结论,只有a=b,或者a与b完全相反时可以变成0
      • 如何构造操作区间,其实只需要对a一位一位全变为0,那么此时a都是0,b要么全为1,要么全为0。全为0则不需要操作,全为1则只需操作[1n],[1,1],[2,n]三次即可
    • 代码

    #include 
    #include 
    
    using namespace std;
    typedef pair<int,int> PII;
    
    void solve() {
        int n; cin>>n;
        string a,b; cin>>a>>b;
        if(a!=b) {//不完全相反
            bool f=1;
            for(int i=0;i<n;i++)
                if(a[i]==b[i]) { f=0; break; }
            if(!f) {cout<<"NO"<<'\n'; return ;}
        }
        cout<<"YES"<<'\n';
        vector<PII> A;
        for(int i=1;i<=n;i++) {
            if(a[i-1]=='1') {
                A.push_back({i,i});
                if(i>1) b[0]=(b[0]=='1' ? '0':'1');
            }
        }
        if(b[0]=='1') { A.push_back({1,n}); A.push_back({1,1}); A.push_back({2,n});}
        cout<<A.size()<<'\n';
        for(auto x:A) cout<<x.first<<' '<<x.second<<'\n';
    }
    
    int main() {
        int t=1; cin>>t;
        while(t--) solve();
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    D. Count GCD

    • 题意

      • 给定一个长度为n的数组a,问有多少个长度为n的数组b符合下列条件
        1 ≤ b i ≤ m , ( m ≤ 1 0 9 ) g c d ( b 1 , b 2 , . . . , b i ) = a i 1\le b_i\le m,(m\le 10^9)\\ gcd(b_1,b_2,...,b_i)=a_i 1bim,(m109)gcd(b1,b2,...,bi)=ai
    • 题解

      • 数论+容斥原理应用。首先先来判断给出的a数组是否能够构造出合法的b数组。gcd(b1,b2,…,bi-1)=ai-1,gcd(b1,b2,…,bi)=gcd(ai-1, bi)=ai,从这里可以看出a数组之间的关系,即a[i]%a[i-1]=0,由此得到a的合法形式,a[i]%a[i-1]=0对于每一个i
      • 如何计算有多少个合法的b数组?对于每一个位置来分析有多少种合法的情况,则b数组的合法数量为n个位置的乘法计数。分析b数组的一个位置:因为gcd(ai-1, bi)=ai,所以gcd(x, y)=1,x,y分别为ai-1,bi对于ai的倍数,即x与y互质,求bi的数量即求y的数量,而x,y的范围为[1, m/a[i]],固bi的数量等价于[1, m/a[i]]的范围内与a[i-1]/a[i]互质的数量。计算方法为容斥原理,参见严格鸽的博客。(简明扼要地说一下,求[1,n]中与k互质的数的个数,只需枚举计算k的质因数排列,通过容斥原理计算数量即可)
      • 最后的答案为n个位置的乘法原理
    • 代码

    #include 
    #include 
    
    using namespace std;
    const int N=2e5+10,mod=998244353;
    typedef long long ll;
    
    int n,m,a[N];
    int num,sum;
    vector<int> primes;
    
    void prime(int x) {//分解质因数
        primes.clear();
        for(int i=2;i*i<=x;i++)
            if(x%i==0) {
                primes.push_back(i);
                while(x%i==0) x/=i;
            }
            
        if(x>1) primes.push_back(x);
    }
    
    void dfs(int pos,int mul,int len) {//搜索枚举每一种质因数的选取情况,用容斥原理计算数量
        if(pos==primes.size()) {
            if(len) {
                if(len%2) sum+=num/mul;
                else sum-=num/mul;
            }
            return ;
        }
        
        dfs(pos+1,mul,len);
        dfs(pos+1,mul*primes[pos],len+1);
    }
    
    int cal(int l,int k) {//计算[1,L]中与k互质的数量
        prime(k);
        num=l,sum=0;
        dfs(0,1,0);
        return l-sum;
    }
    
    int solve() {
        cin>>n>>m;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=2;i<=n;i++)//a数组不合法
            if(a[i-1]%a[i]) return 0;
            
        ll res=1;
        for(int i=2;i<=n;i++) {
            if(a[i]==a[i-1]) res=res*(m/a[i])%mod;//降低复杂度
            else res=res*cal(m/a[i],a[i-1]/a[i])%mod;//计算每一个位置的合法数量
        }
        return res;
    }
    
    int main() {
        int t; cin>>t;
        while(t--) cout<<solve()<<'\n';
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
  • 相关阅读:
    RocketMQ源码环境搭建
    【短道速滑十一】标准的Gabor滤波器及Log_Gabor滤波器的实现、解析、速度优化及其和Halcon中gen_gabor的比较。
    开创性的区块链操作系统项目——去中心化的战舰游戏
    如何用servlet写注册登录页面?
    微信小程序---软件学习(制作小程序软件的安装,创建第一个小程序)
    c++介绍与入门基础(详细总结)
    PyQt学习笔记-使用QSettings保存系统配置参数
    【C++】格式与实例化操作——[模板]详解(7)
    mysql5.7 window启动慢解决方法 最慢启动长达几个小时
    Linux下安装navicat
  • 原文地址:https://blog.csdn.net/m0_49843646/article/details/127760812