计算机学术交流协会程序设计新生赛题解
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机学术交流协会程序设计新生赛题解相关的知识,希望对你有一定的参考价值。
计算机学术交流协会程序设计新生赛题解
比赛链接:
https://vj.wangyaqii.top/contest/4/problems
密码:jsjxsjlxh
1️⃣A 数组的飞升
对于两个数
a
i
,
a
j
a_i,a_j
ai,aj 来说,假设
a
i
≤
a
j
a_i \\leq a_j
ai≤aj,如果要满足题目中总和不下降,即任意两个数之间满足
2
(
a
j
−
a
i
)
≥
a
i
+
a
j
2(a_j-a_i) \\geq a_i + a_j
2(aj−ai)≥ai+aj
解得
a
j
≥
3
a
i
a_j \\geq 3a_i
aj≥3ai
所以只要构造出
1
,
3
,
9
,
27
,
.
.
.
.
1, 3, 9,27,....
1,3,9,27,....即为最优情况,提前算出
3
20
=
1162261467
>
1
0
9
3^20=1162261467\\gt 10^9
320=1162261467>109,故最大长度的数组为
3
0
,
3
1
,
.
.
.
,
3
18
3^0,3^1,...,3^18
30,31,...,318共
19
19
19个
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve()
int n;
cin >> n;
if(n >= 20)
cout << "NO\\n";
return;
cout << "YES\\n";
ll x = 1;
for(int i = 1; i <= n; i++, x *= 3)
cout << x << " \\n"[i == n];
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
// cin >> t;
t = 1;
while(t--)
solve();
return 0;
2️⃣B 小王的疑惑
本题希望用常规做法写,但是因为数据随机生成, n 2 n^2 n2的暴力循环就能过去
下面是 n 2 n^2 n2的暴力循环,判断不相等的个数统计到结果中即可。
#include<bits/stdc++.h>
using namespace std;
int main()
int n;
cin >> n;
vector<int> a(n + 1);
for(int i = 1; i <= n; i++)
cin >> a[i];
int res = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j < i; j++)
if(a[i] != a[j])
res++;
cout << res << "\\n";
return 0;
下面是常规解法
- 求相同的数对个数:
对于每个 a i a_i ai求在 a i a_i ai前面出现了多少次与 a i a_i ai相等的数,把这个个数加到结果上去即可
- 求不同的数对个数:
对于每个 a i a_i ai求在 a i a_i ai前面出现了多少次与 a i a_i ai不相等的数的个数(这个个数等于 i − 1 − c n t [ a [ i ] ] i - 1 - cnt[a[i]] i−1−cnt[a[i]]),把它加到结果上去即可
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve()
int n;
cin >> n;
vector<int>cnt(1e5 + 1, 0);
ll res = 0;
for(int i = 1; i <= n; i++)
int x;
cin >> x;
res += i - 1 - cnt[x];
cnt[x] ++ ;
cout << res << "\\n";
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
// cin >> t;
t = 1;
while(t--)
solve();
return 0;
下面这种做法是:
直接先统计所有数出现的个数,求每个与自己不同的数的个数,即为 n − c n t [ a [ i ] ] n-cnt[a[i]] n−cnt[a[i]],但是由于一个数对中前后各算了一遍,需要对结果除2。
前后两种解法的本质是一样的
#include <iostream>
#include <vector>
using namespace std;
#define int long long
signed main()
int n;cin>>n;
vector<int>a(n),cnt(n+1);
for(int i=0;i<n;i++)cin>>a[i],cnt[a[i]]++;
int res=0;
for(int i=0;i<n;i++)res+=n-cnt[a[i]];
cout<<res/2<<'\\n';
3️⃣C 小A买书
前缀和(高中的数列的前n项和)知识, 注意数据范围
s [ i ] = a [ 1 ] + a [ 2 ] + . . . + a [ i ] s[i] = a[1] + a[2] + ... + a[i] s[i]=a[1]+a[2]+...+a[i]
则
a
[
l
]
+
a
[
l
+
1
]
+
.
.
.
+
a
[
r
]
=
s
[
r
]
−
s
[
l
−
1
]
a[l] + a[l + 1] + ... + a[r] = s[r] - s[l - 1]
a[l]+a[l+1]+...+a[r]=s[r]−s[l−1]
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void solve()
int n;
cin >> n;
vector<ll> s(n + 1);
for(int i = 1; i <= n; i++)
int x;
cin >> x;
s[i] = s[i - 1] + x;
int q;
cin >> q;
while(q--)
int l, r;
cin >> l >> r;
cout << s[r] - s[l - 1] << "\\n";
int main()
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
// cin >> t;
t = 1;
while(t--)
solve();
return 0;
4️⃣D 小源的纸条游戏
当第一轮就有人咳嗽的时候,证明只有一个蓝纸条,因为此时这个蓝纸条看见所有人都是红纸条,所以第一轮就会咳嗽结束游戏
当第二轮才有人咳嗽的时候,证明一个蓝纸条看见除自己外另一个蓝纸条了,不然第一轮就会咳嗽。一个蓝纸条看见除自己以外只有一个蓝纸条,但第一轮没有结束,这时候他就知道自己也是蓝纸条,第二轮就会咳嗽
依次类推,第m轮咳嗽,证明有m个蓝纸条
#include <iostream>
using namespace std;
signed main()
int n,m;
cin>>n>>m;
cout<<m<<endl;
5️⃣E 五只小A
模拟问题
本题在于如何有效处理相同的过程, 相同的过程大部分都使用递归来处理。
d f s ( l e n , x , y ) dfs(len, x, y) dfs(len,x,y)表示长度为 l e n len len的正方形,左上角的坐标为 ( x , y ) (x,y) (x,y)的绘制情况
每次递归的向下进行的情况有五种:
- 左上角的正方形
- 右上角的正方形
- 中间的正方形
- 左下角的正方形
- 右下角的正方形
每次向下递归时长度都要除3,坐标也要进行相应的变换
注意递归到底及时退出(即长度等于1时,并且输出这个字符A
)
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
signed main()
int n;cin>>n;
vector<vector<char>>g(n+1,vector<char>(n+1,' '));
function<void(int,int,int)> dfs = [&](int u,int x,int y)
int d=u/3;
if(u==1)g[x][y]='A';return ;
dfs(d,x,y);
dfs(d,x,y+2*d);
dfs(d,x+d,y+d);
dfs(d,x+2*d,y);
dfs(d,x2021-2022 北京化工大学程序设计新生赛 - 问题 N: 聪明的蚂蚁 - 题解