第16届蓝桥杯c++研究生组题解

个人题解记录,其中F题代码为60%通过代码,D题代码为80%通过代码,其余代码在洛谷数据下皆可ac

A 数位倍数

题目链接

[P12162 蓝桥杯 2025 省 C/研究生组] 数位倍数 - 洛谷

题解

直接计算每个数字的数位和,对数位和是5的倍数的进行统计即可

答案

40500

代码

#include
#define ll long long
#define pii pair<int, int>
#define endl '\n'
using namespace std;
const int N = 2e5 + 10;
int ans;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    for(int i = 1; i <= 202504; i++) {
        int x = i, cnt = 0;
        while(x) {
            cnt += x % 10;
            x /= 10;
        }
        if(cnt % 5 == 0) ans++;
    }
    cout << ans;
    return 0;
}

// 40500

B IPv6

题目链接

[P12185 蓝桥杯 2025 省 Python A/研究生组] IPv6 - 洛谷

题解

dfs,将IPv6码分成8段,通过dfs枚举每一段的长度(0-4)

计算种类数: 每段的种类数为 1 6 l e n − 1 ∗ 15 16^{len-1}*15 16len115(最高位不为0),当前IPv6码总种类数就是每段种类数的乘积

计算IPv6码压缩后长度: 不压缩前长度-压缩的0序列长度,对于0序列的压缩,在序列长度相同的情况下,压缩中间的0序列要比压缩两端的0序列更优

对于已知每段长度的IPv6码,该种情况所有IPv6码的总长度=压缩后长度*种类数

最后将所有情况的总长度相加即为答案

答案

905307083

代码

#include
#define ll long long
#define pii pair<int, int>
#define endl '\n'
using namespace std;
const int mod = 1e9 + 7;
int n = 8, a[10];
ll ans, fact[10];

// 计算IPv6码长度
int get_len() {
	int mx = 0, l = -1, len = 0;
	
	// 不考虑压缩时的总长度len
	for(int i = 1; i <= 8; i++) {
		if(a[i] == 0) len++;
		else len += a[i];
	}
	len += 7;
	
    //l、r表示当前0序列的长度,计算最多压缩长度mx
	for(int r = 1; r <= 8; r++) {
		if(a[r] == 0) {
			if(l == -1) l = r;
			if(r == 8 && l == 1) mx = max(mx, 2 * (r - l) - 1);
			else if(r == 8 || l == 1) mx = max(mx, 2 * (r - l));
			else mx = max(mx, 2 * (r - l) + 1);
		}
		else l = -1;
	}
	return len - mx;
}

void dfs(int x) {
	if(x == n + 1) {
		ll sum = 1;
        // 计算当前的总种类数
		for(int i = 1; i <= 8; i++)
			if(a[i]= 0) sum = sum * fact[a[i] - 1] % mod * 15 % mod;
        
		sum = sum * get_len() % mod;
		ans = (ans + sum) % mod;
		return;
	}
	for(int i = 0; i <= 4; i++) {
		a[x] = i;
		dfs(x + 1);
	}
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    //fact记录16的次方
    fact[0] = 1;
	for(int i = 1; i < 5; i++)
		fact[i] = fact[i - 1] * 16 % mod;
	dfs(1);
	cout << ans;
    return 0;
}

C 变换数组

题目链接

[P12188 蓝桥杯 2025 省 Java A/研究生组] 变换数组 - 洛谷

题解

模拟计算,每次计算出数组每个元素的二进制中1的个数,再与原数进行相乘即可

代码

#include
#define ll long long
#define pii pair<int, int>
#define endl '\n'
using namespace std;
const int N = 1e3 + 10;
int n, m, a[N];

// 计算数字二进制中1的个数
int count(int x) {
    int cnt = 0;
    while(x) {
        cnt += x % 2;
        x /= 2;
    }
    return cnt;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i++)
        cin >> a[i];
    cin >> m;
    while(m--) {
        for(int i = 1; i <= n; i++)
            a[i] *= count(a[i]);
    }
    for(int i = 1; i <= n; i++)
        cout << a[i] << " ";
    return 0;
}

D 最大数字

题目链接

[P12188 蓝桥杯 2025 省 Java A/研究生组] 变换数组 - 洛谷

题解(80%)

排序+高进度

用string类型存储 1 − n 1-n 1n的二进制并进行排序,排序规则为: a + b > b + a a+b>b+a a+b>b+a

对最终组合成的二进制进行高进度求算,最后得到答案

代码

// 80%
#include
#define ll long long
#define pii pair<int, int>
#define endl '\n'
using namespace std;
const int N = 5e6 + 10;
int n, la = 1, lb = 1, ans[N], pls[N];
vector<string> s;
string t;

void mul() {
    int c = 0, w = lb + 1;
    for(int i = 1; i <= w; i++) {
        pls[i] = pls[i] * 2 + c;
        c = pls[i] / 10;
        pls[i] %= 10;
    }
    if(pls[w] != 0) lb++;
}

void add() {
    int c = 0, w = max(la, lb) + 1, t = 0;
    for(int i = 1; i <= w; i++) {
        ans[i] += pls[i] + c;
        c = ans[i] / 10;
        ans[i] %= 10;
        if(ans[i]) t = i;
    }
    la = t;
}

void print() {
    for(int i = la; i >= 1; i--)
        cout << ans[i];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    
    // 将1-n转换为二进制,并进行排序
    for(int i = 1; i <= n; i++) {
        string p = "";
        int x = i;
        while(x) {
            p += (x % 2 + '0');
            x /= 2;
        }
        reverse(p.begin(), p.end());
        s.push_back(p);
    }
    sort(s.begin(), s.end(), [](string a, string b) {
        return a + b > b + a;
    });
    
    // 组合最终答案,并进行高进度计算求解
    for(string x : s)
        t += x;
    reverse(t.begin(), t.end());
    pls[1] = 1;
    for(char c : t) {
        if(c == '1') add();
        mul();
    }
    print();
    return 0;
}

E 冷热数据队列

题目链接

[P12166 蓝桥杯 2025 省 C/Java A/研究生组] 冷热数据队列 - 洛谷

题解

模拟,使用两个队列对题目的所有操作进行模拟

对于2、4条件中的移动元素放入另一队列的操作,使用记录每个元素的在队列里的数量元素当前所在的队列的方法来优化从原队列弹出的操作

如果元素所在的队列和当前队列不符,或者元素在该队列中存在多个,则说明该元素在后续存在其他操作,当前得到的元素是无效的

在队列溢出需要弹出元素时,就可以通过上述方法判断当前得到的元素是否有效

对于无效的数据直接忽略,只对有效的数据进行弹出的对应操作

代码

#include
#define ll long long
#define pii pair<int, int>
#define endl '\n'
using namespace std;
const int N = 1e5 + 10;

int n1, n2, m, s1, s2;
int cnt1[N], cnt2[N], pos[N];	//cnt用于记录每个元素在对应队列中的个数,pos用于记录每个元素当前所在的队列
vector<int> ans1, ans2;
queue<int> q1, q2;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n1 >> n2 >> m;
    while(m--) {
        int x;
        cin >> x;
        // 条件1,元素不在队列中
        if(pos[x] == 0) {
            // 放入队列2,s2用于统计当前队列2中的元素数量
            s2++; q2.push(x);
            cnt2[x]++; pos[x] = 2;
			
            // 对于溢出的元素进行弹出
            while(s2 > n2) {
                int t = q2.front();
                q2.pop(); cnt2[t]--;
                if(pos[t] != 2) continue;
                if(pos[t] == 2 && cnt2[t]) continue;
                s2--; pos[t] = 0;
            }
        }
        // 条件2,元素已队列中
        else {
            if(pos[x] == 2) s2--, s1++;
            q1.push(x); cnt1[x]++; pos[x] = 1;

            while(s1 > n1) {
                int t = q1.front();
                q1.pop(); cnt1[t]--;
                if(pos[t] != 1) continue;
                if(pos[t] == 1 && cnt1[t]) continue;
                s1--;
                if(s2 < n2) {
                    s2++; q2.push(t);
                    cnt2[t]++; pos[t] = 2;
                }
                else pos[t] = 0;
            }
        }
    }
    
    // 将队列中的元素弹出进行输出
    while(!q1.empty()) {
        int t = q1.front();
        q1.pop(); cnt1[t]--;
        if(pos[t] != 1) continue;
        if(pos[t] == 1 && cnt1[t]) continue;
        ans1.push_back(t);
    }
    while(!q2.empty()) {
        int t = q2.front();
        q2.pop(); cnt2[t]--;
        if(pos[t] != 2) continue;
        if(pos[t] == 2 && cnt2[t]) continue;
        ans2.push_back(t);
    }
    reverse(ans1.begin(), ans1.end());
    reverse(ans2.begin(), ans2.end());
    for(int x : ans1)
        cout << x << " ";
    cout << endl;
    for(int x : ans2)
        cout << x << " ";
    return 0;
}

F 01串

题目链接

[P12191 蓝桥杯 2025 省研究生组] 01 串 - 洛谷

题解(60%)

从0开始遍历每个数,暴力统计每个数的二进制位数和其中1的个数

代码

#include
#define ll long long
#define pii pair<int, int>
#define endl '\n'
using namespace std;
const int N = 1e7 + 10;
ll n, bit = 1, fact = 1, sum, num, ans;

// 计算数字的二进制中1的个数
int find(int x) {
    int cnt = 0;
    while(x) {
        cnt += x % 2;
        x /= 2;
    }
    return cnt;
}

// 计算最后那个数在剩余位数中有多少个1
int get(int x, int t) {
    vector<int> bi;
    while(x) {
        bi.push_back(x % 2);
        x /= 2;
    }
    reverse(bi.begin(), bi.end());

    int cnt = 0;
    for(int i = 0; i < t; i++)
        if(bi[i] == 1) cnt++;
    return cnt;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    for(int i = 0; i < N; i++) {
        if(i == fact * 2)
            bit++, fact *= 2;
        if(sum + bit > n) {
            num = i;
            break;
        }
        sum += bit;
        ans += find(i);
    }
    if(sum < n) ans += get(num, n - sum);
    cout << ans;
    return 0;
}

G 甘蔗

题目链接

[P12189 蓝桥杯 2025 省 Java A/研究生组] 甘蔗 - 洛谷

题解

dp,建立二维dp数组, f [ i ] [ j ] f[i][j] f[i][j]表示每根甘蔗在高度为 j j j时,前面甘蔗都符合条件所需的最小砍甘蔗次数

则对于每根甘蔗的每个高度 j j j,都是由前一根的 j + b [ k ] j+b[k] j+b[k] j − b [ k ] j-b[k] jb[k]状态转移得到

(复杂度 O ( n ∗ m ∗ a [ i ] ) O(n*m*a[i]) O(nma[i]),按照题目的数据,复杂度为2e8,在洛谷能ac,不确定是否能通过蓝桥杯的官方数据)

代码

#include
#define ll long long
#define pii pair<int, int>
#define endl '\n'
using namespace std;
const int N = 1e3 + 10;
const int inf = 0x3f3f3f3f;

int n, m, a[N], b[N], f[N][N], ans = inf;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        cin >> a[i];
    for(int i = 1; i <= m; i++)
        cin >> b[i];
    
    // 初始化数据,对于第一根甘蔗,除了原始高度,其他高度均需砍1次
    memset(f, inf, sizeof(f));
    f[1][a[1]] = 0;
    for(int i = 0; i < a[1]; i++)
        f[1][i] = 1;
    
    for(int i = 2; i <= n; i++) {
        // 当前甘蔗也需要砍
        for(int j = 0; j < a[i]; j++) {
            for(int k = 1; k <= m; k++) {
                if(j + b[k] < N) f[i][j] = min(f[i][j], f[i - 1][j + b[k]] + 1);
                if(j - b[k] >= 0) f[i][j] = min(f[i][j], f[i - 1][j - b[k]] + 1);
            }
        }
        // 当前甘蔗不砍
        for(int j = 1; j <= m; j++) {
            if(a[i] + b[j] < N) f[i][a[i]] = min(f[i][a[i]], f[i - 1][a[i] + b[j]]);
            if(a[i] - b[j] >= 0) f[i][a[i]] = min(f[i][a[i]], f[i - 1][a[i] - b[j]]);
        }
    }
    for(int i = 0; i <= a[n]; i++)
        ans = min(ans, f[n][i]);
    if(ans == inf) cout << -1;
    else cout << ans;
    return 0;
}

H 原料采购

题目链接

[P12187 蓝桥杯 2025 省 Python A/Java A/研究生组] 原料采购 - 洛谷

题解

反悔贪心,使用优先队列将已经选择的原料按价格从高到低排列

从前到后选取原料,在选满原料后,将当前原料的价格与已选原料中最高的价格进行比较,若当前价格低于已选原料,则进行替换

将当前的原料费用与路飞相加得到总花费,取最优即可

代码

#include
#define ll long long
#define pii pair<int, int>
#define endl '\n'
using namespace std;
const int N = 1e6 + 10;

ll n, m, o, a[N], b[N], c[N];
ll cnt, tot, sum, ans = 2e18;

struct node {
    ll a, b;
    bool operator < (const node &x) const {
        return a < x.a;
    }
};
priority_queue<node> q;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n >> m >> o;
    for(int i = 1; i <= n; i++) {
        cin >> a[i] >> b[i] >> c[i];
        tot += b[i];
    }
	
    // 特判:原料不足,输出-1
    if(tot < m) {
        cout << -1;
        return 0;
    }

    for(int i = 1; i <= n; i++) {
        // 原料未选够时直接加入当前原料
        if(cnt + b[i] <= m) {
            q.push({a[i], b[i]});
            cnt += b[i];
            sum += a[i] * b[i];
        }
        else {
            if(cnt < m) {
                q.push({a[i], m - cnt});
                b[i] -= m - cnt;
                sum += a[i] * (m - cnt);
                cnt = m;
            }
            //否则,将当前原料与所选的最高价格进行对比替换
            while(!q.empty() && b[i]) {
                node t = q.top();
                if(t.a <= a[i]) break;
                q.pop();
                if(b[i] >= t.b) {
                    q.push({a[i], t.b});
                    b[i] -= t.b;
                    sum -= (t.a - a[i]) * t.b;
                }
                else {
                    q.push({a[i], b[i]});
                    q.push({t.a, t.b - b[i]});
                    sum -= (t.a - a[i]) * b[i];
                    b[i] = 0;
                }
            }
            ans = min(ans, sum + c[i] * o);
        }
    }
    cout << ans;
    return 0;
}

你可能感兴趣的:(蓝桥杯,c++,算法,动态规划,数据结构,深度优先)