1550: [蓝桥杯2021初赛] 卡片
#include <bits/stdc++.h>
using namespace std;
int a[15] = {2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021};
int main() {
int ans = 1;
while(1) {
int temp = ans;
while(temp != 0) {
int t = temp % 10; temp /= 10;
if(a[t] - 1 < 0) {
ans -= 1; cout << ans << endl;
return 0;
}
else a[t] --;
}
ans += 1;
}
}
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << 3181 << endl;
return 0;
}
1551: [蓝桥杯2021初赛] 直线
#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9;
set<pair<double, double> > s;
int main() {
int x1, y1, x2, y2;
for(x1 = 0; x1 < 20; x1 ++) {
for(y1 = 0; y1 < 21; y1 ++) {
for(x2 = 0; x2 < 20; x2 ++) {
for(y2 = 0; y2 < 21; y2 ++) {
if(x1 == x2) s.insert({INF, x1});
else {
double k = (double)(y2-y1)/(x2-x1);
double b = (double)(y1*(x2-x1)-x1*(y2-y1))/(x2-x1);
s.insert({k, b});
}
}
}
}
}
cout << s.size() << endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main() {
cout << 40257 << endl;
return 0;
}
1552: [蓝桥杯2021初赛] 货物摆放
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long LL;
LL n = 2021041820210418;
LL a[3000], cnt = 0, res = 0;
int main() {
for(int i = 1; i <= sqrt(n); i ++) {
if(n % i == 0) {
a[++ cnt] = i;
if(i*i != n) a[++ cnt] = n / i;
}
}
for(int l = 1; l <= cnt; l ++) {
for(int w = 1; w <= cnt; w ++) {
for(int h = 1; h <= cnt; h ++) {
if(a[l]*a[w]*a[h] == n) res++;
}
}
}
cout << res;
return 0;
}
#include <iostream>
using namespace std;
int main()
{
cout << 2430 << endl;
return 0;
}
1553: [蓝桥杯2021初赛] 路径
#include<bits/stdc++.h>
#define ll long longusing namespace std;
int dist[2100];
int g[2100][2100];
bool st[2100];
int gcd(int x,int y){
return x%y ? gcd(y, x%y) : y;
}
int dijkstra() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for(int i = 0; i < 2021; i ++) {
int t = -1;
for( int j = 1; j <= 2021; j ++ ) {
if(!st[j] && (t == -1 || dist[t] > dist[j])) {
t = j;
}
}
st[t] = true;
for(int j = 1; j <= 2021; j ++) {
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
}
if(dist[2021] == 0x3f3f3f3f) return -1;
return dist[2021];
}
int main() {
memset(g, 0x3f3f3f3f, sizeof g);
for(int i = 1; i <= 2021; i ++) g[i][i]=0;
for(int i = 1; i <= 2021; i ++) {
for(int j = i+1; j <= 2021 && j <= i+21; j ++) {
int w = i*j / gcd(i, j);
g[i][j] = g[j][i] = min(g[i][j], w);
}
}
int t = dijkstra();
printf("%d\n", t);
return 0;
}
#include <iostream>
using namespace std;
int main()
{
cout << 10266837 << endl;
return 0;
}
1555: [蓝桥杯2021初赛] 空间
#include <bits/stdc++.h>
using namespace std;
int main() {
long long ans = 256*1024/32;
cout << ans*1024*8 << endl;
return 0;
}
1558: [蓝桥杯2021初赛] 砝码称重
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int dp[100005]; // 为 1 是可以称出 为 0 是不可以称出
int w[105]; // 记录每一个砝码的重量
int main() {
int n; cin >> n;
memset(dp, 0, sizeof dp); dp[0] = 1;
for(int i = 1; i <= n; i ++) cin >> w[i];
for(int i = 1; i <= n; i ++) {
for(int j = 100000; j >= w[i]; j --) {
dp[j] = max(dp[j], dp[j-w[i]]);
}
}
for(int i=1;i<=n;i++){
for(int j = 1; j <= 100000-w[i]; j ++) {
dp[j] = max(dp[j], dp[j+w[i]]);
}
}
int ans = 0;
for(int i = 1; i <= 100000; i ++) ans += dp[i];
cout << ans << endl;
}
1561: [蓝桥杯2021初赛] 括号序列
题意是,给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。
首先对于本题来说,最关键的就是合法括号的定义,即对于任意前缀,左括号的数量都要大于右括号的数量,这样才可以使得括号合法。
然后就是通过计算,求解出添加最少的左括号数量,根据合法括号序列的性质,只需在每个右括号之前添加左括号使其满足前缀性质,那么显然该序列被右括号分成了,一共是右括号数量+1段,那么只需在每一段添加一个左括号即可使其合法。
定义 f[i][j] 表示对于前 i 个字符,左括号数量比右括号数量多 j 个的集合。可以分析得到状态转移方程为:
f[i][j] = f[i][j-1] + f[i-1][j+1]
从而可以通过解决本题。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 5100, mod = 1e9 + 7;
LL f[N][N];
int n;
char s[N];
LL solve() {
memset(f, 0, sizeof f);
f[0][0] = 1;
for(int i = 1; i <= n; i ++) {
if(s[i] == '(') {
for(int j = 1; j <= n; j ++) {
f[i][j] = f[i - 1][j - 1];
}
}
else {
f[i][0] = (f[i - 1][0] + f[i - 1][1]) % mod;
for(int j = 1; j <= n; j ++) {
f[i][j] = (f[i][j - 1] + f[i - 1][j + 1]) % mod;
}
}
}
for(int i = 0; i <= n; i++) {
if(f[n][i]) return f[n][i];
}
return 0;
}
int main() {
scanf("%s", s + 1); n = strlen(s + 1);
LL x = solve();
reverse(s + 1, s + 1 + n);
for(int i = 1; i <= n; i ++) {
if(s[i] == '(') s[i] = ')';
else s[i] = '(';
}
LL y = solve();
cout << x * y % mod << endl;
return 0;
}
1563: [蓝桥杯2021初赛] 时间显示
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
LL DTime = 86400000;
LL HTime = 3600000, MTime = 60000, STime = 1000;
int T; cin >> T;
while(T --) {
int H, M, S;
long long Time; cin >> Time;
Time %= DTime;
H = Time / HTime; Time %= HTime;
M = Time / MTime; Time %= MTime;
S = Time / STime;
printf("%02d:%02d:%02d\n", H, M, S);
}
return 0;
}
1564: [蓝桥杯2021初赛] 杨辉三角形
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[2005][2005];
int main() {
int T; cin >> T;
while(T --) {
LL N, flag = 0; cin >> N;
memset(a, 0, sizeof a);
a[0][0] = 1;
for(int i = 1; i < 2005; i ++) {
for(int j = 1; j <= i; j ++) {
a[i][j] = a[i-1][j] + a[i-1][j-1];
if(a[i][j] == N && flag == 0) {
cout << i*(i-1)/2+j <<endl;
flag = 1;
}
}
}
if(flag == 0) {
LL n = sqrt(N*2) + 1;
if(n*(n-1)/2 == N) cout << n*(n+1)/2+3 << endl;
else cout << N*(N+1)/2+2 << endl;
}
}
return 0;
}
1565: [蓝桥杯2021初赛] 双向排序
分析题目可以得到,题目中一共设计了两种操作,一个是选定前 x 个数,使其降序,另一个是选定后 y 个数,使其升序。
对于可能出现的所有操作方式,考虑全部的情况:
1.连续出现多个操作1,即从当前位置往后全部为升序,所以只需要找到最小的那个位置,即找到连续操作 1 的最长区间,这样可以通过最长的一个区间升序,即可满足多个操作的实现。
2.连续的多个操作0,同理也是去取最长的区间进行降序的操作,从而一步实现多个操作。
3.操作0与操作1交替,需要去找两次不同操作的相交区间,操作1和2交替进行,且相比于上一次操作,本次操作的区间长度越来越短,因此相交部分也越来越短,直到两者不再相交,到这时修改将不再起作用,每次操作其实反转的也只有相交部分。故多次翻转的情况下,会使得相交的区间逐渐缩减,最后得以确定出整个的排序序列。
通过对于三种不同情况的分析,最后可以解决出本题。
#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 100010;
int n, m, ans[N];
PII stk[N];
int main() {
scanf("%d%d", &n, &m);
int top = 0;
while(m --) {
int p, q; scanf("%d%d", &p, &q);
if (!p) {
while(top && stk[top].x == 0) q = max(q, stk[top --].y); //出现连续的操作1,我们取最大
while(top >= 2 && stk[top-1].y <= q) top -= 2; //如果当前的操作1比上一次的操作1范围大,则将上一次操作1和操作2删除
stk[++ top] = {0, q};//存本次最佳操作
}
else if(top) { //操作2 &&且操作1已经进行过(操作二第一个用没效果)
while(top && stk[top].x == 1) q = min(q, stk[top --].y);
while(top >= 2 && stk[top-1].y >= q) top -= 2;
stk[++ top] = {1, q};
}
}
int k = n, l = 1, r = n;
for(int i = 1; i <= top; i ++) {
if (stk[i].x == 0) {
while(r > stk[i].y && l <= r) ans[r --] = k -- ;
}
else {
while(l < stk[i].y && l <= r) ans[l ++] = k -- ;
}
if (l > r) break;
}
if(top % 2) {
while (l <= r) ans[l ++ ] = k -- ;
}
else {
while (l <= r) ans[r -- ] = k -- ;
}
for(int i = 1; i <= n; i ++) printf("%d ", ans[i]);
return 0;
}