圈钱杯第十一、十二届C++ B组省赛真题

A.空间

在这里插入图片描述

( ( 256 * 1024 ) * 1024 ) / 4
1 MB = 1024 KB 1KB = 1024B 1B = 8 bit位 = 8 二进制位
67108864

B.卡片

在这里插入图片描述

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main()
{
    int a[10];
    for(int i = 0; i <= 9; i ++ ) a[i] = 2021;
    
    int ans = 1, i = 0;
    while(true)
    {
        i = ans;
        while(i)
        {
            a[i % 10] -- ;
            if(a[i % 10] <= 0)
            {
                cout << ans << endl;
                return 0;
            }
            i /= 10;
        }
        ans ++ ;
    }
    return 0;
}
C.直线

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>

using namespace std;

const int N = 200000;    // 最多有 20 * 20 个点, 400 * 400 个不同组合·

int n;
struct Line     // 直线方程 y = k * x + b , 用 k,b 区分不同直线
{
    double k, b;
    bool operator< (const Line& t) const // k, b 递增排序
    {
        if(k != t.k) return k < t.k;    
        return b < t.b;
    }
}l[N];  // 用 (k, b) 区分存放不同的直线方程

int main()
{
    for(int x1 = 0; x1 < 20; x1 ++ )
        for(int y1 = 0; y1 < 21; y1 ++ )
            for(int x2 = 0; x2 < 20; x2 ++ )
                for(int y2 = 0; y2 < 21; y2 ++ )
                    if(x1 != x2)
                    {
                        double k = (double) (y2 - y1) / (x2 - x1);
                        double b = y1 - k * x1;
                        l[n ++ ] = {k, b};
                    }
    sort(l, l + n);
    int res = 1;    // 统计不同 k, b 的直线方程有多少条
    for(int i = 1; i <n; i ++ )
        if(fabs(l[i].k - l[i - 1].k) > 1e-8 || fabs(l[i].b - l[i - 1].b) > 1e-8)    // 部分斜率、截距之间的差值非常微小
        res ++;
    cout << res + 20 << endl;   // 20 为 k = 0 时垂直于x轴的直线
    
    return 0;
}		// 40257
D.货物摆放

在这里插入图片描述

#include <iostream>
#include <vector>

typedef long long LL;

using namespace std;

int main()
{
    LL n = 2021041820210418;
    cin >> n;
    vector<LL> d;
    for(LL i = 1; i * i <= n; i ++ )
        if(n % i == 0)
        {
            d.push_back(i);
            if(n / i != i) d.push_back(n / i);
        }
        
    int res = 0;
    for(auto a: d)
        for(auto b: d)
            for(auto c: d)
                if(a * b * c == n)
                    res ++;
    cout << res << endl;
    
    return 0;
}
// 暴力枚举
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

typedef long long LL;

int main()
{
    LL n = 2021041820210418, res = 0;
    for(LL i = 1; i <= n; i ++ )
        if(n % i == 0)
            for(LL j = 1; j <= n; j ++ )
                if(n / i % j == 0)
                {
                    LL k = n / i / j;
                    if(i == j && j == k) res ++;
                    else if(i != j & j != k) res += 6;
                    else res += 3;
                }
    cout << res << endl;
    return 0;
}
E.路径*

在这里插入图片描述

… …

F.时间显示*
G.砝码称重

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

// DP 背包
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110, M = 200010, B = M / 2;

int n, m;
int w[N];
bool f[N][M];

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++ ) scanf("%d", &w[i]), m += w[i];
    
    f[0][B] = true;
    for (int i = 1; i <= n; i ++ )
        for(int j = -m; j <= m; j ++ )
        {
            f[i][j + B] = f[i - 1][j + B];
            if(j - w[i] >= -m) f[i][j + B] |= f[i - 1][j - w[i] + B];
            if(j + w[i] <= m) f[i][j + B] |= f[i - 1][j + w[i] + B];
        }
        
    int res = 0;
    for(int j = 1; j <= m; j ++ )
        if(f[n][j + B]) 
            res ++;
    printf("%d\n", res);
    return 0;
}
H.杨辉三角

在这里插入图片描述


#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

int n;
/*
    组合数和杨辉三角:第i行第j列的数都是组合数C(i, j) (i,j从0开始)
        C(n, 1) = n --> 对应从左向右看斜着的第二列! ---> 一定有解
    由于杨辉三角左右对称(C(a, b) == C(a, a-b)),又由于找第一次出现,因此一定在左边,右边可以直接删掉!

            1  ---> C(0, 0)
          1 
        1   2  ---> C(2, 1)
      1   3                             ---> C(2n, n)
    1   4   6  ---> C(4, 2)
  1   5   10
1   6   15  20 ---> C(6, 3)

    n最大1e9,C(34, 17) > 1e9, C(32, 16) < 1e9,因此只要枚举前16个斜行即可!


    性质:
        1. 每一斜行从上到下递增
        2. 每一横行从中间到两边依次递减

    因此我们直接从中间对称轴倒序二分找起即可!

        C(r, k)对应的顺序值为:(r + 1) * r / 2 + k + 1

        二分的左右端点:l:2k,r:max(n, l)
            右端点一定不能比左端点小!
            特例:否则当n=1时,会出问题!

*/
// C(a, b) = a!/b!(a-b)! = a * (a-1) .. b个 / b!
LL C(int a, int b){
    LL res = 1;
    for(int i = a, j = 1; j <= b; i --, j ++){
        res = res * i / j;
        // 大于n已无意义,且防止爆LL
        if(res > n) return res;
    }
    return res;
}

bool check(int k){
    // 二分该斜行,找到大于等于该值的第一个数
    // 左边界2k,右边界为max(l, n)取二者最大即可!
    int l = 2 * k, r = max(n, l);
    while(l < r){
        int mid = l + r >> 1;
        if(C(mid, k) >= n) r = mid;
        else l = mid + 1;
    }
    if(C(r, k) != n) return false;
    // C(r, k)的从0开始的顺序!
    cout << 1ll * (r + 1) * r / 2 + k + 1 << endl;
    return true;
}

int main(){
    cin >> n;
    // 从第16斜行枚举即可!
    for(int k = 16; ; k --)
        if(check(k)) break;
    return 0;
}
I.双向排序*
J.括号序列*

第十一届

A.门牌制作

在这里插入图片描述

#include <bits/stdc++.h>

using namespace std;
// 1~2020需要多少个字符2

int ans = 0;

void check(int i)
{
    while(i > 0)
        {
            if(i % 10 == 2) ans ++ ;
            i /= 10;
        }
}
int main()
{
    for(int i = 1; i <= 2020; i ++ ) check(i);
    cout << ans << endl;
    return 0;
}   // 624
B.既约分数

在这里插入图片描述

#include <bits/stdc++.h>

using namespace std;
// 1~2020有多少个既约分数的组合  不可同 / 2 3 5 7 

int ans = 0;

int gcd(int a, int b)
{
    /*if(a % 2 == b % 2 || a % 3 == b % 3 || a % 5 == b % 5 || a % 7 == b % 7) return;
    else ans += 2 ;*/
    if(a % b == 0) return b;
    return gcd(b, a % b);
}
int main()
{
    for(int i = 1; i <= 2020; i ++ )
        for(int j = i + 1; j <= 2020; j ++ )
            if(gcd(i, j) == 1) ans ++ ;
// 分子分母可互换 * 2 ;  1/1  2/2  3/3 ... 属于同一种情况  + 1
    cout << ans * 2 + 1 << endl;
    return 0;
}   // 2481215
C.蛇形填数

在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int x  = 0;
    for(int i = 1; i <= 19; i ++ ) x += i;
    cout << 5 + x * 4 << endl;
}	// 找规律
D.跑步锻炼

在这里插入图片描述

#include <bits/stdc++.h>

using namespace std;


int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int main()
{
    int day = 1, month = 1, year = 2000, weekday =6, cnt = 0;
    while(1)
    {
        cnt += (day == 1 || weekday == 1) + 1;   // 周一或月初 +1
        if(year == 2020 && month == 10 && day == 1) break;
        
        day ++ ;
        weekday = (weekday + 1) % 7;
        
        if(month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0))  // 二月并且是闰年
        {
            if(day > days[month] + 1)   // 29号后遍历下一个月
            {
                day = 1;
                month ++ ;
            }
        }
        else if(day > days[month])
        {
            day = 1;a
            month ++ ;
        }
        if(month == 13)
        {
            year ++ ;
            month = 1;
        }
    }
    cout << cnt << endl;
    return 0;
}
E.七段码*

在这里插入图片描述

F.成绩统计

在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;

int a[10010];
int n;

int main()
{
    cin >> n;
    int qsum = 0, esum = 0;
    for(int i = 1; i <= n; i ++ ) 
    {
        cin >> a[i];
        if(a[i] >= 60) qsum ++ ;
        if(a[i] >= 85) esum ++ ;
    }
    
    int q_sum = (qsum * 1000 / n) , e_sum = (esum * 1000 / n);

    if(q_sum % 10 >= 5) q_sum += 10;
    if(e_sum % 10 >= 5) e_sum += 10;
    
    cout << q_sum / 10 << "%" << endl << e_sum / 10 << "%" << endl;
    return 0;
}

整除序列

在这里插入图片描述

#include <iostream>

using namespace std;

int main()
{
    long long n;
    cin >> n;
    
    while(n)
    {
        cout << n << ' ';
        n /= 2;
    }
    
    return 0;
}// 3181
解码

在这里插入图片描述

#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    string s, res;  // s存放每次读入的字符串, res 存放最终输出的字符串结果
    cin >> s;
    
    for(int i = 0; i < s.size(); i ++ )
    {
        if(i + 1 < s.size() && s[i + 1] <= '9')    // 任何一个大小写英文字母的ascii码都 >'9'
        {
            int k = s[i + 1] - '0';     //  存放数字--循环打印s[i]字符的次数
            while(k -- ) res += s[i];
            i ++;       // 字符 s[i] 打印 s[i + 1] 次后继续遍历下一个字符
        }
        else res += s[i];   // s[i + 1] 处不是数字,字符s[i]仅打印一次则直接加入
    }
    
    cout << res << endl;
    return 0;
}
走方格

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <cstring>

using namespace std;

const int N = 40;
int f[N][N];    // f[i][j] 表示从起点走到 (i, j) 共有多少种方案
int n, m;

int main()
{
    cin >> n >> m;
    f[1][1] = 1;    // 最开始在格子1,方案数为1

    for(int i = 1; i <= n; i ++ )
        for(int j = 1; j <= m; j ++ )
        {
            if(i == 1 && j == 1) continue;
            if(i % 2 || j % 2)      //保证行列不能同时为偶数  (i % 2 || j % 2) 其中两个条件都为偶数则 0
                f[i][j] = f[i - 1][j] + f[i][j - 1];
        }
        
    cout << f[n][m] << endl;
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值