Title

蓝桥杯2024C/C++省A(持续更新)

蓝桥杯2024C/C++省A(持续更新)

训练士兵

贪心

思路

将所有士兵按照训练次数从小到大排序(如果能团购的话团购的次数肯定是当前所有士兵次数的最小值)

当前训练此时所有士兵所有花费为sum, 团购为s,比较ssum

  1. s>sum,不团购了,自己花钱训练

  2. 否则就选择团购

注意过程中要维护当前的sum和士兵训练次数

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 1e18;

struct custom_hash 
{
	static uint64_t splitmix64(uint64_t x) 
    {
		x ^= x << 13;
		x ^= x >> 7;
		x ^= x << 17;
		return x; 
	}
	size_t operator () (uint64_t x) const 
    {
		static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
		return splitmix64(x + FIXED_RANDOM);
	}
};
int a[maxn], b[maxn];
struct Node
{
    int pri, cnt;
}node[maxn];

bool cmp(Node a, Node b)
{
    return a.cnt < b.cnt;
}

void solve()
{
    int n = 0, s = 0;
    std::cin >> n >> s;
    int sum = 0;
    for (int i = 1; i <= n; i++)
    {
        std::cin >> node[i].pri >> node[i].cnt;
        sum += node[i].pri;
    }
    std::sort(node + 1, node + 1 + n, cmp);
    int ans = 0;
    int cur = 0; // 团购的次数
    for (int i = 1; i <= n; i++)
    {
        if (s < sum)
        {
            ans += s * (node[i].cnt - cur);
            cur += (node[i].cnt- cur);
            sum -= node[i].pri;
        }
        else
        {
            ans += node[i].pri * (node[i].cnt - cur);
            sum -= node[i].pri;
        }
    }
    std::cout << ans << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}

五子棋对弈

思路

有些像填数独

最难的部分还是判断,我们可以暴力判断每一行每一列和两条对角线,还要判断是否是轮流下棋,也就是一个下了13次,一个下了12

检查次数

int cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= 5; i++)
{
    for (int j = 1; j <= 5; j++)
    {
        if (mat[i][j] == 1)
        {
            cnt1++;
        }
        else
        {
            cnt2++;
        }
    }
}
if (cnt1 - cnt2 != 1) return false;

检查每一行

// 检查每一行
for (int i = 1; i <= 5; i++)
{
    bool flag = true;
    for (int j = 1; j <= 5; j++)
    {
        if (mat[i][j] != mat[i][1])
        {
            flag = false;
            break;
        }
    }
    if (flag) return false;
}

检查每一列

// 检查每一列
for (int i = 1; i <= 5; i++)
{
    bool flag = true;
    for (int j = 1; j <= 5; j++)
    {
        if (mat[j][i] != mat[1][i])
        {
            flag = false;
            break;
        }
    }
    if (flag) return false;
}

检查对角线

// 检查对角线
// 主对角线 i == j
// 副对角线 i + j == 6
bool f1 = true;
for (int i = 1; i <= 5; i++)
{
    if (mat[i][i] != mat[1][1])
    {
        f1 = false;
        break;
    }
}
if (f1) return false;
bool f2 = true;
for (int i = 1; i <= 5; i++)
{
    if (mat[i][6 - i] != mat[1][5])
    {
        f2 = false;
        break;
    }
}
if (f2) return false;
return true;

以下代码耗时大约4s

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 1e18;

struct custom_hash 
{
	static uint64_t splitmix64(uint64_t x) 
    {
		x ^= x << 13;
		x ^= x >> 7;
		x ^= x << 17;
		return x; 
	}
	size_t operator () (uint64_t x) const 
    {
		static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
		return splitmix64(x + FIXED_RANDOM);
	}
};

int mat[7][7];

bool check()
{
    int cnt1 = 0, cnt2 = 0;
    for (int i = 1; i <= 5; i++)
    {
        for (int j = 1; j <= 5; j++)
        {
            if (mat[i][j] == 1)
            {
                cnt1++;
            }
            else
            {
                cnt2++;
            }
        }
    }
    if (cnt1 - cnt2 != 1) return false;
    // 检查每一行
    for (int i = 1; i <= 5; i++)
    {
        bool flag = true;
        for (int j = 1; j <= 5; j++)
        {
            if (mat[i][j] != mat[i][1])
            {
                flag = false;
                break;
            }
        }
        if (flag) return false;
    }
    // 检查每一列
    for (int i = 1; i <= 5; i++)
    {
        bool flag = true;
        for (int j = 1; j <= 5; j++)
        {
            if (mat[j][i] != mat[1][i])
            {
                flag = false;
                break;
            }
        }
        if (flag) return false;
    }
    // 检查对角线
    // 主对角线 i == j
    // 副对角线 i + j == 6
    bool f1 = true;
    for (int i = 1; i <= 5; i++)
    {
        if (mat[i][i] != mat[1][1])
        {
            f1 = false;
            break;
        }
    }
    if (f1) return false;
    bool f2 = true;
    for (int i = 1; i <= 5; i++)
    {
        if (mat[i][6 - i] != mat[1][5])
        {
            f2 = false;
            break;
        }
    }
    if (f2) return false;
    return true;
}

int ans = 0;

void dfs(int x, int y)
{
    if (y == 6) // 这一列走完了
    {
        dfs(x + 1, 1);
        return;
    }
    if (x == 6) // 最后一行走完了
    {
        if (check()) ans++;
        return;
    }
    mat[x][y] = 1;
    dfs(x, y + 1);
    mat[x][y] = 2;
    dfs(x, y + 1);
    mat[x][y] = 0;
}

void solve()
{
    dfs(1, 1);
    std::cout << ans << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    int s = clock();
    while(t--)
    {
        solve();
    }
    int d = clock();
    std::cout << d - s << endl;
    return 0;
}

考虑剪枝优化

cnt1cnt2不符合条件时直接返回false

具体步骤为

  1. dfs 函数中添加全局变量或传递参数来跟踪当前的 cnt1cnt2
  2. 计算剩余的单元格数。
  3. 判断是否有可能通过填充剩余单元格使得最终 cnt1cnt2==1
  4. 如果不可能,立即返回,停止进一步的递归。

以下代码耗时约600ms

(其实复杂度并没有改变,仍为O(225))

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 1e18;

struct custom_hash 
{
	static uint64_t splitmix64(uint64_t x) 
    {
		x ^= x << 13;
		x ^= x >> 7;
		x ^= x << 17;
		return x; 
	}
	size_t operator () (uint64_t x) const 
    {
		static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
		return splitmix64(x + FIXED_RANDOM);
	}
};

int mat[7][7];

bool check()
{
    // 检查每一行
    for (int i = 1; i <= 5; i++)
    {
        bool flag = true;
        for (int j = 1; j <= 5; j++)
        {
            if (mat[i][j] != mat[i][1])
            {
                flag = false;
                break;
            }
        }
        if (flag) return false;
    }
    // 检查每一列
    for (int i = 1; i <= 5; i++)
    {
        bool flag = true;
        for (int j = 1; j <= 5; j++)
        {
            if (mat[j][i] != mat[1][i])
            {
                flag = false;
                break;
            }
        }
        if (flag) return false;
    }
    // 检查对角线
    // 主对角线 i == j
    // 副对角线 i + j == 6
    bool f1 = true;
    for (int i = 1; i <= 5; i++)
    {
        if (mat[i][i] != mat[1][1])
        {
            f1 = false;
            break;
        }
    }
    if (f1) return false;
    bool f2 = true;
    for (int i = 1; i <= 5; i++)
    {
        if (mat[i][6 - i] != mat[1][5])
        {
            f2 = false;
            break;
        }
    }
    if (f2) return false;
    return true;
}

int ans = 0;

void dfs(int x, int y, int c1, int c2)
{
    if (y == 6)
    {
        dfs(x + 1, 1, c1, c2);
        return;
    }
    if (x == 6)
    {
        if (c1 - c2 == 1 && check()) ans++;
        return;
    }

    // 剩余的格子
    int rest = 25 - 5 * (x - 1) - (y - 1) - 1;
    mat[x][y] = 1;
    if (c1 + 1 - c2 + rest >= 1)
    {
        dfs(x, y + 1, c1 + 1, c2);
    }
    mat[x][y] = 2;
    if (c1 - (c2 + 1) + rest >= 1)
    {
        dfs(x, y + 1, c1, c2 + 1);
    }
    mat[x][y] = 0;
}

void solve()
{
    dfs(1, 1, 0, 0);
    std::cout << ans << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr); std::cout.tie(nullptr);
    //freopen("out.txt", "w", stdout);
    int t = 1;
    //std::cin >> t;
    //int s = clock();
    while(t--)
    {
        solve();
    }
    //int d = clock();
    //std::cout << d - s << endl;
    return 0;
}

成绩统计

思路

让我们把式子拆开看一看

σ2=i=1k(viv¯)2k
Sk为这k个数的和

i=1k(viv)2=i=1k(vi2+v¯22v¯vi)=i=1kvi2+kv¯22v¯i=1kvi=i=1kvi2Sk2k

我们只需要维护一个前缀平方和和一个前缀和就好了

x就用二分查找就好了

时间复杂度O(n)

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using ld = long double;
const int maxn = 2e5 + 5;
const int inf = 1e10;
const ld eps = 1e-15;
struct custom_hash 
{
	static uint64_t splitmix64(uint64_t x) 
    {
		x ^= x << 13;
		x ^= x >> 7;
		x ^= x << 17;
		return x; 
	}
	size_t operator () (uint64_t x) const 
    {
		static const uint64_t FIXED_RANDOM = std::chrono::steady_clock::now().time_since_epoch().count(); // 时间戳
		return splitmix64(x + FIXED_RANDOM);
	}
};

inline int read()
{
    int x = 0, flag = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if (ch == '-')
        {
            flag = -1;
        }
        ch = getchar();
    }
    while (ch <= '9' && ch >= '0')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * flag;
    
}
int n = 0, k = 0;
int T = 0;
bool check(std::vector<int> nums, int pos)
{
    if (pos < k) return false;
    std::sort(nums.begin() + 1, nums.begin() + 1 + pos);
    std::vector<int> pre(pos + 1, 0), pre2(pos + 1, 0);
    for (int i = 1; i <= pos; i++)
    {
        pre[i] = pre[i - 1] + nums[i] * nums[i];
        pre2[i] = pre2[i - 1] + nums[i];
    }   
    for (int i = 1; i + k - 1 <= pos; i++)
    {
        ld t = (ld)(pre[i + k - 1] - pre[i - 1]);
        ld s = (ld)(pre2[i + k - 1] - pre2[i - 1]);
        ld t2 = (ld)(s * s) / (ld)k;
        if ((ld)k * T - (t - t2) > eps) return true;
    }
    return false;
}   

void solve()
{
    std::cin >> n >> k >> T;
    std::vector<int> nums(n + 1, 0);
    for (int i = 1; i <= n; i++)
    {
        std::cin >> nums[i];
    }
    int l = 0, r = n + 1;
    while(l + 1 < r)
    {
        int mid = (l + r) >> 1;
        if (check(nums, mid))
        {
            r = mid;
        }
        else
        {
            l = mid;
        }
    }
    if (r == n + 1)
    {
        printf("%d", -1);
    }
    else
    {
        printf("%lld", r);
    }
}

signed main()
{
    //freopen("out.txt", "w", stdout);
    int t = 1;
    // t = read();
    //int s = clock();
    while(t--)
    {
        solve();
    }
    //int d = clock();
    //std::cout << d - s << endl;
    return 0;
}

posted @   栗悟饭与龟功気波  阅读(35)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示