• 2022年ACM暑假集训个人排位赛(1)A-F题解


    A: 剩余的数量

    题意
    现有S和T字符串,其数量分别是A和B
    现给你一个字符串U,U=S或者U=T,使其数量-1
    问S和T现在的数量是多少
    思路
    模拟
    时间复杂度 O 1 O1 O1

    #include<bits/stdc++.h>
    using namespace std ;
    const int N = 1e6 + 10 ;
    string a , b , s ;
    int ca , cb ;
    
    int main()
    {
        cin >> a >> b >> ca >> cb >> s ;
        if(a == s) ca -- ;
        else cb -- ;
        cout << ca << " " << cb << "\n" ;
        
        return 0 ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    B: 替换字符

    题意
    给你一个字符串,将其中所有字符都替换为x并输出
    思路
    模拟
    时间复杂度 O n On On

    #include<bits/stdc++.h>
    using namespace std ;
    const int N = 1e6 + 10 ;
    
    int main()
    {
        string s ;
        cin >> s ;
        for(auto i : s) cout << 'x' ;
        return 0 ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    C: 相同或者不同

    题意
    给你n个数的数组
    a 1 a_1 a1 a 2 a_2 a2 a n a_n an
    问是否所有数都不一样
    是输出YES
    否则输出NO
    思路
    用map记录一下每个数的出现次数
    只要有一个数的出现次数大于等于2次
    输出NO即可
    否则输出YES
    时间复杂度 O n l o g n Onlogn Onlogn

    #include<bits/stdc++.h>
    using namespace std ;
    const int N = 1e6 + 10 ;
    map<int,int> q ;
    int f , n , x ;
    
    int main()
    {
        cin >> n ;
        while(n --)
        {
            scanf("%d",&x) ;
            q[x] ++ ;
            if(q[x] >= 2) f = 1 ; 
        }
        puts((f == 1 ? "NO" : "YES")) ;
        
        return 0 ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    D: 排成一行的骰子

    题意
    我们把 n个骰子从左到右排成一行
    左侧第 i 个骰子显示 p i p_i pi , p i p_i pi表示这个骰子可以抛出的点数范围为[1, p i p_i pi],每个点抛出的概率相等
    我们将选择k个相邻的骰子,分别投掷每个骰子,并计算所示数字的总和。
    查找此总和的期望值的最大可能值。
    思路
    对每个骰子来说,每个点数抛出的概率相等为 1 / p i 1/p_i 1/pi
    所以每个骰子的点数的期望为
    1 / p i ∗ ( 1 + 2 + 3 + . . . . . + p i ) 1/p_i*(1+2+3+.....+p_i) 1/pi(1+2+3+.....+pi)
    1 / p i ∗ ( p i ) ∗ ( p i + 1 ) / 2 1/p_i*(p_i) * (p_i+1)/2 1/pi(pi)(pi+1)/2
    化简得
    ( 1 + p i ) / 2 (1 + p_i)/2 (1+pi)/2
    题目求的是连续k个骰子的期望和的最大值
    用前缀和优化一下即可

    时间复杂度 O n On On

    #include<bits/stdc++.h>
    using namespace std ;
    const int N = 1e6 + 10 ;
    int n , k ;
    double a[N] , s[N] ;
    
    int main()
    {
        cin >> n >> k ;
        for(int i = 1 ; i <= n ; i ++)
        {
            cin >> a[i] ;
            s[i] = s[i - 1] + (a[i] + 1.0) / 2.0 ;
        }
        
        double v = 0 ;
        for(int i = 1 ; i + k - 1 <= n ; i ++)
        {
            v = max(v , s[i + k - 1] - s[i - 1]) ;
        }
        
        printf("%.12lf",v) ;
        
        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

    E: 到处都是0

    题意
    求1到N(包括1和N)之间的整数的数目,
    这些整数恰好包含K个非0数字
    思路
    在这里插入图片描述

    首先我们把 n n n的每一位保存到一个数组里面

    我们从这个数的最高位往最低位遍历

    假设现在遍历到了最高位
    0 0 0 a n − 1 a_{n}-1 an1的任意数字,记为x
    x_ _ _ _ _ _ _ _ _ 后面有n-1个位置
    通过动态规划可以计算出来

    我们用 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]来表示一共有 i i i位,最高位填 j j j,当前一共有 k k k个非 0 0 0数字的方案数
    状态转移方程为
    f [ i + 1 ] [ z ] [ k + ( z ! = 0 ) ] + = f [ i ] [ j ] [ k ] ; f[i + 1][z][k + (z != 0)] += f[i][j][k] ; f[i+1][z][k+(z!=0)]+=f[i][j][k];

    x_ _ _ _ _ _ _ _ _ 后面有n-1个位置
    所以该方案数为 f [ n ] [ x ] [ k ] f[n][x][k] f[n][x][k]
    表示一共有 n n n位,最高位填的是 x x x,有 k k k个非 0 0 0数字的情况下的方案数

    填完 a n a_n an之后,继续往这颗树上继续填,直到不能填为止

    时间复杂度 O ( 100 n ) O(100n) O(100n)

    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #define int long long
    using namespace std;
    
    const int N = 110;
    
    int f[N][10][5] , m ;
    char s[N] ;
    
    void init()  // 求动态规划方程
    {
        for (int i = 0; i <= 9; i ++ ) f[1][i][(i != 0)] = 1;
    
        for (int i = 1; i <= N - 10; i ++ )
            for (int j = 0; j <= 9; j ++ )
                for(int z = 0 ; z <= 9 ; z ++)
                    for(int k = 0 ; k <= 3 ; k ++)
                        f[i + 1][z][k + (z != 0)] += f[i][j][k] ;
                
    }
    
    void dp()
    {
        vector<int> nums;
        
        cin >> s + 1 >> m ;
        for(int i = strlen(s + 1) ; i >= 1 ; i --)
            nums.push_back(s[i] - '0') ;
    
        int res = 0;
        int last = 0;  // last表示之前高位填的数中有多少个非0数
        for (int i = nums.size() - 1; i >= 0; i -- )
        {
            int x = nums[i];     // 当前位的数字
            if(last > m) break ;  // 高位已经填了k+1个非0数 直接break即可
            
            //cout << i << " " << x << " " << last << '\n' ;
            
            for(int j = 0 ; j < x ; j ++)
                res += f[i + 1][j][m - last] ;
            
            //cout << res << '\n' ;
            
            if(x != 0) last ++ ;  // 统计高位的非0数
    
            if (!i && last == m) res ++ ;  // 如果这个数本身也符合题意  答案++
        }
    
        cout << res << '\n' ;
    }
    
    signed main()
    {
        init();
        
        dp() ;
        
        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
    • 63

    F: 路径数目

    题意

    小梁站在一个二维平面上。在一次操作中,他可以在正x方向移动1,或在正y方向移动1。
    让我们定义一个函数f(r,c),如下所示:
    f ( r , c ) f(r,c) f(rc)=从点(0,0)到点(r,c)的路径数
    现在给你 r 1 , c 1 , r 2 , c 2 r1 , c1 , r2 , c2 r1,c1,r2,c2

    ∑ i = r 1 r 2 ∑ j = c 1 c 2 f ( i , j ) \sum_{i=r1}^{r2}{\sum_{j=c1}^{c2}f(i,j)} i=r1r2j=c1c2f(i,j)

    思路

    首先,从 ( 0 , 0 ) (0,0) (0,0)走到 ( i , j ) (i,j) (i,j)的方案数为 C ( i + j , i ) C(i+j,i) C(i+j,i)
    表示必须走 i + j i+j i+j步,必须走 i i i步横着的或者是 j j j步竖着的

    开始推式子

    ∑ i = r 1 r 2 ∑ j = c 1 c 2 f ( i , j ) \sum_{i=r1}^{r2}{\sum_{j=c1}^{c2}f(i,j)} i=r1r2j=c1c2f(i,j)

    等价于
    ∑ i = r 1 r 2 ∑ j = c 1 c 2 C i + j i \sum_{i=r1}^{r2}{\sum_{j=c1}^{c2}C_{i+j}^{i}} i=r1r2j=c1c2Ci+ji

    因为
    C n + m + 1 m + 1 = ∑ i = 0 n C m + i m C_{n+m+1}^{m+1} = \sum_{i=0}^{n}{C_{m+i}^{m}} Cn+m+1m+1=i=0nCm+im

    所以原式等于
    ∑ i = r 1 r 2 C i + c 2 + 1 i + 1 − C i + c 1 + 1 − 1 i + 1 \sum_{i=r1}^{r2}{C_{i+c2+1}^{i+1}-C_{i+c1+1-1}^{i+1}} i=r1r2Ci+c2+1i+1Ci+c1+11i+1

    预处理阶乘和阶乘的逆元即可O n n n计算

    时间复杂度 O n l o g n Onlogn Onlogn

    #include<bits/stdc++.h>
    #define int long long 
    using namespace std ;
    const int N = 3e6 + 10 , mod = 1e9 + 7 ;
    
    int fact[N] , infact[N];
    int qmi(int a , int b , int mod)
    {
        int res = 1 ;
        while(b)
        {
            if(b & 1) res = (res * a) % mod ;
            b >>= 1 ;
            a = a * a  % mod ;
        }
        return res;
    }
    int c(int a , int b)
    {
        if(b > a) return 0 ;
        return fact[a] % mod * infact[b] % mod * infact[a - b] % mod ;
    }
    void init(int n)
    {
        fact[0] = infact[0] = 1 ;
        for(int i = 1 ; i <= n ; i ++)
        {
            fact[i] = fact[i-1] % mod  * i % mod ;
            infact[i] = infact[i - 1] * qmi(i, mod - 2, mod) % mod;
        }
    }
    
    signed main()
    {
        init(N - 10) ;
        int r1 , c1 , r2 , c2 ;
        cin >> r1 >> c1 >> r2 >> c2 ;
        
        int res = 0 ;
        for(int i = r1 ; i <= r2 ; i ++)
        {
            res = (res + c(i + c2 + 1 , i + 1) - c(i + c1 + 1 - 1 , i + 1)) % mod ;
            res = (res % mod + mod) % mod ;
        }
        
        cout << res << '\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
  • 相关阅读:
    骨传导耳机和气传导区别有哪些?骨传导和气传导耳机科普
    基于JavaScript的模拟键盘Web实现——可用作个人博客主页
    【python笔记】第三节 用户交互与运算符
    JC/T 482-2022 聚氨酯建筑密封胶检测
    exe打包 帮我看一下怎么回事
    解决quest2激活后更新卡0%(内附全套工具)
    OceanBase社区版单节点安装搭建(Docker)
    代码随想录算法训练营DAY29(记录)|C++回溯算法Part.5|491.递增子序列、46.全排列、47.全排列II
    第六章:利用dumi搭建组件文档【前端工程化入门-----从零实现一个react+ts+vite+tailwindcss组件库】
    优秀智慧园区案例 - 三亚市崖州湾科技城智慧园区,先进智慧园区建设方案经验
  • 原文地址:https://blog.csdn.net/yueshehanjiang/article/details/125551970