【2023年第十四届蓝桥杯C/C++ A组省赛】个人题解

目录

A:幸运数

解题思路

参考代码

B:有奖问答

解题思路

参考代码

C:平方差

解题思路

参考代码

D:更小的数

解题思路

参考代码

E:颜色平衡树

解题思路

参考代码        

F:买瓜

解题思路

参考代码        

G:网络稳定性

解题思路

参考代码        

H:异或和之和

解题思路

参考代码

I:像素放置

解题思路

参考代码

J:翻转硬币

解题思路

参考代码

A:幸运数

解题思路

思路1:枚举1到100000000,跑的比较慢

思路2:因为是偶数,可以折半枚举,快多了,但是不能在1s内跑出来

思路3:动态规划,用表示前个数(包括)中,数位和为的数的个数,已经可以在1s内跑出来了O(K*36*9999)

 思路4:状态优化,用表示位数为的数中,数位和为的数的个数 O(K*9999)

参考代码

参考代码1

#include
using namespace std;
bool cheak(int x) {
	string s = to_string(x);
	int len = s.size();
	if (len % 2 == 1) return 0;
	int s1 = 0, s2 = 0;
	int l = 0, r = len - 1;
	while (l < r) {
		s1 += s[l] - '0';
		s2 += s[r] - '0';
		l++, r--;
	}
	if (s1 != s2) return 0;
	return 1;
}
int cnt;
int main() {
	for (int i = 1; i <= 100000000; i++) {
		if (cheak(i)) cnt++;
	}
	cout << cnt;
	return 0;
}

参考代码2

#include
using namespace std;
int sum[10000];
int s_num(int x) {
	int s = 0;
	while (x) {
		s += x % 10;
		x /= 10;
	}
	return s;
}
int cnt;
int main() {
	for (int i = 1; i <= 9999; i++) sum[i] = s_num(i);
	for (int k = 0; k <= 3; k++) {
		for (int i = pow(10, k); i < pow(10, k + 1); i++) {
			for (int j = 1; j < pow(10, k + 1); j++) {
				if (sum[i] == sum[j]) cnt++;
			}
		}
	}
	cout << cnt;
	return 0;
}

参考代码3

#include
using namespace std;
int sum[10000];
int f[50][10000];
int s_num(int x) {
	int s = 0;
	while (x) {
		s += x % 10;
		x /= 10;
	}
	return s;
}
int cnt;
int main() {
	for (int i = 1; i <= 9999; i++) sum[i] = s_num(i);
	for (int i = 1; i <= 9999; i++) {
		for (int j = 1; j <= 36; j++) f[j][i] = f[j][i - 1];
		f[sum[i]][i]++;
	}
	for (int k = 0; k <= 3; k++) {
		int j = pow(10, k + 1) - 1;
		for (int i = pow(10, k); i <= j; i++) {
			cnt += f[sum[i]][j];
		}
	}
	cout << cnt;
	return 0;
}

参考代码4

#include
using namespace std;
int sum[10000];
int f[50][5];
int s_num(int x) {
	int s = 0;
	while (x) {
		s += x % 10;
		x /= 10;
	}
	return s;
} 
int cnt;
int main() {
	for (int i = 1; i <= 9999; i++) sum[i] = s_num(i);
	for (int k = 0; k <= 3; k++) {
		int j = pow(10, k + 1) - 1;
		for (int i = 1; i <= 9 * (k + 1); i++) f[i][k + 1] += f[i][k];
		for (int i = pow(10, k); i <= j; i++) {
			f[sum[i]][k + 1]++;
		}
	}
	for (int k = 0; k <= 3; k++) {
		int j = pow(10, k + 1) - 1;
		for (int i = pow(10, k); i <= j; i++) {
			cnt += f[sum[i]][k + 1];
		}
	}
	cout << cnt;
	return 0;
}

B:有奖问答

解题思路

思路1:暴力搜索,比较慢,得跑几秒才能有答案

思路2:动态规划,f_{i,j}表示第i次答题时,当前分数为j*10的方案数,那么答案即为ans=\sum_{i=1}^{30}f_{i,7}

参考代码

参考代码1

#include
using namespace std;
int ans;
void dfs(int k, int sum) {
	if (sum == 7) ans++;
	if (k > 30 || sum == 10)  return;
	dfs(k + 1, 0);
	dfs(k + 1, sum + 1);
}
int main() {
	dfs(1, 0);
	cout << ans;
	return 0;
}

参考代码2

#include
using namespace std;
#define ll long long
ll f[50][15];
int main() {
	f[0][0] = 1;
	for (int i = 1; i <= 30; i++) {
		for (int j = 0; j <= 9; j++) f[i][0] += f[i - 1][j];
		for (int j = 1; j <= 10; j++) {
			f[i][j] = f[i - 1][j - 1];
		}
	}
	ll ans = 0;
	for (int i = 1; i <= 30; i++) ans += f[i][7];
	cout << ans;
	return 0;
}

C:平方差

解题思路

解题思路1:暴力枚举每个平方的差值,然后从左到右扫(40分)

解题思路2:暴力模拟发现,不满足的数符合2+4*k,那么直接扫一遍,把不满足的数筛走即可,但是不能过极限数据(l=1,r=1e9)(100分) O(r-l+1)

解题思路3:因为有规律,其实只用找出两端不满足的数的下标L,R,那么答案ans=(r-l+1)-[(R - L) / 4 + 1]

解题思路4:2+4*k 既是2的倍数但又不是4的倍数的数,那么不满足的个数为区间内2的倍数减去4的倍数,O(1)

参考代码

参考代码1

#include
using namespace std;
#define ll long long
const int N = 1e7;
ll l, r;
bool is[N + 5];
void init() {
	for (int i = sqrt(N); i >= 0; i--) {
		for (int j = i - 1; j >= 0; j--) {
			is[i * i - j * j] = 1;
		}
	}
}
ll ans;
int main() {
	init();
	cin >> l >> r;
	for (int i = l; i <= r; i++) {
		if (is[i]) ans++;
	}
	cout << ans;
	return 0;
}

参考代码2

#include
using namespace std;
#define ll long long
ll l, r;
ll ans;
int main() {
	cin >> l >> r;
	ans = r - l + 1;
	for (int i = l; i <= r; i++) {
		if ((i - 2) % 4 == 0) ans--;
	}
	cout << ans;
	return 0;
}

参考代码3

#include
using namespace std;
#define ll long long
ll l, r;
ll ans;
int main() {
	cin >> l >> r;
	ans = r - l + 1;
	int L, R;
	for (int i = l; i <= r; i++) {
		if ((i - 2) % 4 == 0) {
			L = i;
			break;
		}
	}
	for (int i = r; i >= l; i--) {
		if ((i - 2) % 4 == 0) {
			R = i;
			break;
		}
	}
	ans -= (R - L) / 4 + 1;
	cout << ans;
	return 0;
}

参考代码4

#include
using namespace std;
#define ll long long
ll l, r;
ll ans;
int main() {
	cin >> l >> r;
	ans = (r / 2 - (l - 1) / 2) - (r / 4 - (l - 1) / 4);
	cout << r - l + 1 - ans;
	return 0;
}

D:更小的数

解题思路

解题思路1:直接枚举每一种方法(100分)

参考代码

参考代码1

#include
using namespace std;

int n;
string s;
int ans;

int main() {
	cin >> s;
	n = s.size();
	s = ' ' + s;

	for (int l = 1; l + 1 <= n; l++) {
		for (int r = l + 1; r <= n; r++) {
			for (int k = 1; k <= (r - l + 1) / 2; k++) {
				if (s[r - k + 1] < s[l + k - 1]) {
					ans++;
					break;
				} else if (s[r - k + 1] > s[l + k - 1]) break;
			}
		}
	}

	cout << ans;
	return 0;
}

E:颜色平衡树

解题思路

参考代码        

F:买瓜

解题思路

解题思路1:直接暴搜(20分)

解题思路2:暴搜+玄学剪枝(60分)

解题思路3:折半搜索 (60分)

解题思路4:暴搜+玄学排序剪枝(100昏)(洛谷上过了)

参考代码   

参考代码1

#include
using namespace std;
#define ll long long
const int N = 1e2 + 5;
ll n, m;
ll a[N];
int  ans = 999;
void dfs(int pre, int k, int sum) {
	if (sum == m) {
		ans = min(k, ans);
		return;
	}
	for (int i = pre + 1; i <= n; i++) {
		dfs(i, k, sum + a[i]);
		dfs(i, k + 1, sum + a[i] / 2);
	}
}
int main() {
	cin >> n >> m;
	m *= 2;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		a[i] *= 2;
	}
	dfs(0, 0, 0);
	if (ans != 999) cout << ans;
	else cout << -1;
	return 0;
}

参考代码2     

#include
using namespace std;
#define ll long long
const int N = 1e2 + 5;
ll n, m;
ll a[N], s[N];
int  ans = 999;
void dfs(int pre, int k, int sum) {
	if (k > ans || sum > m || sum + (s[n] - s[pre]) < m) return;
	if (sum == m) {
		ans = min(k, ans);
		return;
	}
	for (int i = pre + 1; i <= n; i++) {
		dfs(i, k, sum + a[i]);
		dfs(i, k + 1, sum + a[i] / 2);
	}
}
int main() {
	cin >> n >> m;
	m *= 2;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		a[i] *= 2;
		s[i] = s[i - 1] + a[i];
	}
	dfs(0, 0, 0);
	if (ans != 999) cout << ans;
	else cout << -1;
	return 0;
}

参考代码3

#include
using namespace std;
#define ll long long
const int N = 1e2 + 5;
ll n, m;
ll a[N];
int  ans = 999;
struct node {
	int val, cnt;
	friend bool operator < (node a, node b) {
		return 1;
	}
};
sets1, s2;
void dfs(int k, int sum, int l, int r, set&st) {
	if (sum > m) return;
	st.insert({sum, k});
	for (int i = l + 1; i <= r; i++) {
		dfs( k, sum + a[i], i, r, st);
		dfs( k + 1, sum + a[i] / 2, i, r, st);
	}
}
int main() {
	cin >> n >> m;
	m *= 2;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		a[i] *= 2;
	}
	dfs(0, 0, 0, n / 2, s1);
	dfs(0, 0, n / 2, n, s2);
	for (auto i : s1) {
		for (auto j : s2) {
			if (i.val + j.val == m) ans = min(ans, i.cnt + j.cnt);
		}
	}
	if (ans != 999) cout << ans;
	else cout << -1;
	return 0;
}

 参考代码4

#include
using namespace std;
#define ll long long
const int N = 1e2 + 5;
ll n, m;
ll a[N], s[N];
int  ans = 999;
void dfs(int pre, int k, int sum) {
    if (k > ans || sum > m || sum + (s[n] - s[pre]) < m) return;
    if (sum == m) {
        ans = k;
        return;
    }
    for (int i = pre + 1; i <= n; i++) {
        dfs(i, k, sum + a[i]);
        dfs(i, k + 1, sum + a[i] / 2);
    }
}
bool cmp(int a, int b) {
    return a > b;
}
int main() {
    cin >> n >> m;
    m *= 2;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        a[i] *= 2;
    }
    sort(a + 1, a + n + 1, cmp);
    for (int i = 1; i <= n; i++) {
        s[i] = s[i - 1] + a[i];
    }
    dfs(0, 0, 0);
    if (ans != 999) cout << ans;
    else cout << -1;
    return 0;
}

G:网络稳定性

解题思路

参考代码        

H:异或和之和

解题思路

解题思路1:暴力枚举每一个区间,(60分)

解题思路2:

参考代码

参考代码1

#include
using namespace std;
#define ll long long
const int N = 1e5 + 5;
ll n, x;
ll a[N];
ll sum;
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) {
		x = 0;
		for (int j = i; j <= n; j++) {
			x ^= a[j];
			sum += x;
		}
	}
	cout << sum;
	return 0;
}

参考代码2

I:像素放置

解题思路

参考代码

J:翻转硬币

解题思路

参考代码

你可能感兴趣的:(蓝桥杯,c++,蓝桥杯)