2021第十二届4月蓝桥杯大赛软件类B组C/C++省赛目录
好多题目事后发现错了,真的血亏TAT。
试题 A:空间(结果填空)
题意:
做法:1ll * 256 * 1024 * 1024 * 8 / 32
答案:67108864
试题 B:卡片(结果填空)
题意:
做法:这题一定要注意是最多能从1拼到多少。
代码:
#include<bits/stdc++.h>
using namespace std;
int a[10];
int solve(int x) {
while(x) {
if(!a[x%10]) return 0;
--a[x%10];
x /= 10;
}
return 1;
}
int main() {
for(int i = 0; i < 10; ++i) a[i] = 2021;
int cnt = 1;
while(1) {
if(!solve(cnt)) break;
++cnt;
}
cout << cnt - 1;
return 0;
}
答案:3181
试题 C:直线(结果填空)
题意:
做法:枚举每两个点,最后check函数判重,暴力写法。
代码:
#include<bits/stdc++.h>
#define eps 1e-9
using namespace std;
const int N = 1e7;
struct xx {
double k, b;
}p[N];
int tot;
void check(double x1, double y1, double x2, double y2) {
double k, b;
k = (y2-y1)/(x2-x1); b = y1 - k*x1;
int f = 1;
for(int i = 1; i <= tot; ++i) {
if(fabs(k - p[i].k) < eps && fabs(b - p[i].b) < eps) {
f = 0; break;
}
}
if(f) p[++tot] = xx {k, b};
}
int main() {
int n = 20, m = 21;
for(double x1 = 0; x1 < n; ++x1) {
for(double y1 = 0; y1 < m; ++y1) {
for(double x2 = 0; x2 < n; ++x2) {
for(double y2 = 0; y2 < m; ++y2) {
if(x1 == x2 || y1 == y2) continue;
check(x1, y1, x2, y2);
}
}
}
}
cout << tot+n+m;
return 0;
}
答案:40257
试题 D:货物摆放(结果填空)
题意:
做法:正确做法是质因子分解把,因为是填空题于是用暴力写了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
vector<LL> ve;
int main() {
LL n = 2021041820210418;
LL sq = sqrt(n);
for(LL i = 1; i <= sq; ++i) {
if(n%i == 0) {
ve.push_back(i);
if(i != n/i) ve.push_back(n/i);
}
}
sort(ve.begin(), ve.end());
int nn = ve.size(), res = 0;
for(int i = 0; i < nn; ++i) {
for(int j = 0; j < nn; ++j) {
if(ve[j] > n/ve[i]) break;
for(int k = 0; k < nn; ++k) {
if(ve[i] > n/(ve[j]*ve[k])) break;
if(ve[i]*ve[j]*ve[k] == n) ++res;
}
}
}
cout << res;
return 0;
}
答案:2430
试题 E:路径(结果填空)
题意:
做法:建边+dijsktra跑最短路。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL, int> pli;
const int N = 1e4;
const int M = 1e7;
struct xx {
int to, nxt;
LL w;
}e[M];
int head[N], tot;
void Add(int u, int v, LL w) {
e[++tot] = xx{v, head[u], w};
head[u] = tot;
}
LL dis[N];
int vis[N];
priority_queue< pli, vector<pli>, greater<pli> > pq;
void dij() {
for(int i = 0; i <= 2021; ++i) dis[i] = 1e18, vis[i] = 0;
dis[1] = 0;
pq.push(make_pair(dis[1], 1));
int u, v;
while(!pq.empty()) {
u = pq.top().second; pq.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
v = e[i].to;
if(dis[v] > dis[u] + e[i].w) {
dis[v] = dis[u] + e[i].w;
pq.push(make_pair(dis[v], v));
}
}
}
}
int main() {
for(int i = 1; i <= 2021; ++i) {
for(int j = i+1; j <= 2021; ++j) {
if(j-i <= 21) {
LL w = i*j/__gcd(i, j);
Add(i, j, w); Add(j, i, w);
}
}
}
dij();
cout << dis[2021];
return 0;
}
答案:10266837
测评网站:Acwing,更新中~
以下代码保证正确性,通过了Acwing的数据。
试题 F:时间显示(程序设计)
题意:
做法:首先取余一天的时间,最后剩下不到一天的时间再分别除以时分秒,每步取余就可以得到啦。
代码:
#include<bits/stdc++.h>
using namespace std;
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (int i = (n); i < (m); ++i)
#define _rep(n,m,i) for (int i = (n); i <= (m); ++i)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-8
#define rint int
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<int, int> mii;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
int f = 1; res = 0;
char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
res *= f;
}
const int ne[8][2] = {1, 0, -1, 0, 0, 1, 0, -1, -1, -1, -1, 1, 1, -1, 1, 1};
const int INF = 0x3f3f3f3f;
const int N = 3e5+10;
const LL Mod = 1e9+7;
const int M = 1e6+10;
int main() {
LL t; cin >> t;
LL day_ms = 24 * 60 * 60 * 1000, h_ms = 60 * 60 * 1000, m_ms = 60 * 1000, s_ms = 1000;
t %= day_ms;
int h, m, s;
h = t / h_ms; t %= h_ms;
m = t / m_ms; t %= m_ms;
s = t / s_ms; t %= s_ms;
printf("%02d:%02d:%02d\n", h, m, s);
return 0;
}
试题 G:砝码称重(程序设计)
题意:
做法:动态规划,这道题可以转换为一个问题,对这n个数字相互之间可以进行加法和减法,每个数字只能用一次,问可以得到多少个不同的数字。那么dp[i]设置有两个状态,0或者1,对于每个a[i],进行两次动态规划,第一次dp[j]=max(dp[j],dp[j-a[i]]),表示只有加法的时候j是否能被得到(0得不到,1能得到),第二次dp[j]=max(dp[j],dp[j+a[i]])表示在加法的基础上增加减法后j是否能被得到,最后统计1至Max中有多少个j,满足dp[j]=1。
代码:
#include<bits/stdc++.h>
using namespace std;
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (int i = (n); i < (m); ++i)
#define _rep(n,m,i) for (int i = (n); i <= (m); ++i)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-8
#define rint int
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<int, int> mii;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
int f = 1; res = 0;
char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
res *= f;
}
const int ne[8][2] = {1, 0, -1, 0, 0, 1, 0, -1, -1, -1, -1, 1, 1, -1, 1, 1};
const int INF = 0x3f3f3f3f;
const int N = 110;
const LL Mod = 1e9+7;
const int M = 1e5+10;
int a[N], dp[M];
int main() {
int n; scanf("%d", &n);
int Max = 0;
_rep(1, n, i) scanf("%d", &a[i]), Max += a[i];
dp[0] = 1;
_rep(1, n, i) {
for(int j = Max; j >= a[i]; --j) dp[j] = max(dp[j], dp[j-a[i]]);
}
_rep(1, n, i) {
_rep(0, Max-a[i], j) dp[j] = max(dp[j], dp[j+a[i]]);
}
int res = 0;
_rep(1, Max, i) if(dp[i]) ++res;
printf("%d\n", res);
return 0;
}
试题 H:杨辉三角形(程序设计)
题意:
做法:放上一张长一点的杨辉三角图(比赛时可以打表打出来)。
通过这张图可以看出来:
1、只要行数足够大,第二左斜列可以包含所有的数。
2、中间的数涨的非常快。
可以大致算一下C(3000, 3)>1e9,那么在第3000行以后有贡献的值就只有C(n,2)了。所以对于前3000行,用c数组存下来所有数(这里小心爆精度,所以一旦大于了1e9,把c的值赋为1e9+1,这样的话后面由它推到的数都可被认为无意义的数)。
代码:
#include<bits/stdc++.h>
using namespace std;
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (int i = (n); i < (m); ++i)
#define _rep(n,m,i) for (int i = (n); i <= (m); ++i)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-8
#define rint int
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<int, int> mii;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
int f = 1; res = 0;
char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
res *= f;
}
const int ne[8][2] = {1, 0, -1, 0, 0, 1, 0, -1, -1, -1, -1, 1, 1, -1, 1, 1};
const int INF = 0x3f3f3f3f;
const int N = 3010;
const LL Mod = 1e9+7;
const int M = 1e6+10;
LL c[N][N];
map<LL, int> mp;
int main() {
c[0][1] = 1; mp[1] = 1;
_rep(1, 3000, i) _rep(0, i, j) {
if(c[i-1][j] + c[i-1][j+1] <= 1e9) {
c[i][j+1] = c[i-1][j] + c[i-1][j+1];
if(!mp[c[i][j+1]]) mp[c[i][j+1]] = (1+i)*i/2+j+1;
} else c[i][j+1] = 1e9 + 1;
}
int n; scanf("%d", &n);
if(mp[n]) printf("%d\n", mp[n]);
else printf("%lld\n", 1ll*(1+n)*n/2+2);
return 0;
}
试题 I:双向排序(程序设计)
题意:
做法:在大佬的帮助下,终于AC了!
做这种思维题的时候我们要先观察一下性质:
- 我们先假设两次操作为 [ 0 , x ] [0,x] [0,x], [ 0 , y ] [0,y] [0,y], 当 x < y x < y x<y 我们发现第一次操作会无效, 当 x > y x > y x>y 第二次操作其实也是无效的,也就是对于连续的同类型操作可以只保留一个,降序保留最大的,升序保留最小的,也就等价于保留使区间变的最大的,其结果不变。
- 由于刚开始的时候数组是升序的,所以我们可以认为刚开始有一个操作 [ 1 , 1 ] [1,1] [1,1],再由性质1可以得出最后必定是 1 , 0 1,0 1,0操作交替出现的。我们再来考虑相邻的相同操作(指的是对于10交替出现的次序中的相邻操作),这里就用0操作来说明。对于两个相邻的0操作, [ 0 , x ] [0,x] [0,x], [ 1 , z ] [1,z] [1,z], [ 0 , y ] [0,y] [0,y],当 x < y x < y x<y 时,我们发现 [ 0 , x ] [0,x] [0,x]操作是无效的,因为它会被 [ 0 , y ] [0,y] [0,y]覆盖掉,当 [ 1 , z ] , [ 0 , y ] [1,z],[0,y] [1,z],[0,y]没有交集时, [ 0 , y ] [0,y] [0,y]操作也是无效的,但是不影响结果。也就是说最终相邻相同操作肯定是区间减少的,也就是1操作是递增的,0操作是递减的。相邻不同操作间肯定是有交集的。
- 假设我们利用上面的性质处理出来了最终的有效操作序列,那我们该要怎么求结果呢,这一步其实更简单一点,我们发现相邻两个操作的交集就是可能还会再被改变的地方,那么它的补集就是不会变的地方。不变的地方肯定是有序的,根据它最后是被1操作影响还是0操作影响来填进数组里面。
我们来举例说明。假设数组长度是9,最终的有效操作是 [ 1 , 1 ] [ 0 , 7 ] , [ 1 , 5 ] , [ 0 , 6 ] [1,1] [0,7],[1,5],[0,6] [1,1][0,7],[1,5],[0,6]。
[
0
,
7
]
[0,7]
[0,7]和
[
1
,
1
]
[1,1]
[1,1]的交集是
(
1
,
7
)
(1,7)
(1,7),补集是
(
8
,
9
)
(8,9)
(8,9)。
7 6 5 4 3 2 1 | 8 9
[
1
,
5
]
[1,5]
[1,5]和
[
0
,
7
]
[0,7]
[0,7]的交集是
(
1
,
4
)
(1,4)
(1,4),补集是
(
7
,
5
)
(7,5)
(7,5)。
7 6 5 | 1 2 3 4
[
0
,
6
]
[0,6]
[0,6]和
[
1
,
5
]
[1,5]
[1,5]的交集是
(
3
,
1
)
(3,1)
(3,1),补集是
(
4
,
4
)
(4,4)
(4,4)。
3 2 1 | 4
最终的结果是7 6 5 3 2 1 4 8 9
代码:
#include<bits/stdc++.h>
using namespace std;
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define _for(n,m,i) for (int i = (n); i < (m); ++i)
#define _rep(n,m,i) for (int i = (n); i <= (m); ++i)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define PI acos(-1)
#define eps 1e-8
#define rint int
typedef long long LL;
typedef pair<LL, int> pli;
typedef pair<int, int> pii;
typedef pair<double, int> pdi;
typedef pair<LL, LL> pll;
typedef pair<double, double> pdd;
typedef map<int, int> mii;
typedef map<char, int> mci;
typedef map<string, int> msi;
template<class T>
void read(T &res) {
int f = 1; res = 0;
char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); }
res *= f;
}
const int ne[8][2] = {1, 0, -1, 0, 0, 1, 0, -1, -1, -1, -1, 1, 1, -1, 1, 1};
const int INF = 0x3f3f3f3f;
const int N = 1e5+10;
const LL Mod = 1e9+7;
const int M = 1e6+10;
struct xx {
int op, a;
}xl[N];
int st[N], tp;
int re[N];
int main() {
int n, m;
scanf("%d%d", &n, &m);
_rep(1, m, i) scanf("%d%d", &xl[i].op, &xl[i].a);
xl[0].op = 1; xl[0].a = 1; st[tp] = 0;
_rep(1, m, i) {
if(xl[st[tp]].op) {
if(xl[i].op) {
if(xl[i].a < xl[st[tp]].a) tp--;
else continue;
}
} else {
if(!xl[i].op) {
if(xl[i].a > xl[st[tp]].a) tp--;
else continue;
}
}
if(xl[i].op) {
while(tp >= 1 && xl[st[tp-1]].a >= xl[i].a) tp -= 2;
} else {
while(tp >= 1 && xl[st[tp-1]].a <= xl[i].a) tp -= 2;
}
st[++tp] = i;
}
int l = 1, r = n, ll, rr, cnt = n, wll = 0;
_rep(1, tp, i) {
//找上下两个操作中序列中需要改变的部分
if((i&1) && (xl[st[i-1]].a < xl[st[i]].a)) {
rr = r; r = xl[st[i]].a;
for(int i = rr; i > r; --i) re[i] = cnt--;
wll ^= 1;
}
else if(!(i&1) && (xl[st[i-1]].a > xl[st[i]].a)) {
ll = l; l = xl[st[i]].a;
for(int i = ll; i < l; ++i) re[i] = cnt--;
wll ^= 1;
}
else break;
}
if(!wll) {
for(int i = r; i >= l; --i) if(!re[i]) re[i] = cnt--;
} else {
for(int i = l; i <= r; ++i) if(!re[i]) re[i] = cnt--;
}
//cout << "----------------" << endl;
_rep(1, n, i) printf("%d%c", re[i], i==n ? '\n' : ' ');
return 0;
}
/*
3 3
0 3
1 2
0 2
*/
试题 J:括号序列(程序设计)
题意:
做法:
代码: