2021-2022-2 ACM集训队每周程序设计竞赛题解
Posted ZZXzzx0_0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-2022-2 ACM集训队每周程序设计竞赛题解相关的知识,希望对你有一定的参考价值。
A. 21点游戏
题意:
给你三个数A1 , A2 , A3 ,
如果A1 + A2 + A3 >= 22 , 输出 bust
否则输出 win
思路:
模拟
时间复杂度:
O
1
O1
O1
#include<bits/stdc++.h>
using namespace std ;
const int N = 1e6 + 10 ;
int main()
int a , b , c ;
cin >> a >> b >> c;
int s = a + b + c ;
if(s >= 22) puts("bust") ;
else puts("win") ;
return 0 ;
B. 回文游戏
题意:
给你一个字符串S,
你可以修改S的任意一个字符,
问最少需要修改多少次,使得S变成一个回文串。
思路:
双指针
时间复杂度:
O
n
On
On
#include<bits/stdc++.h>
using namespace std ;
const int N = 1e6 + 10 ;
char s[N] ;
int main()
cin >> s + 1 ;
int n = strlen(s + 1) ;
int res = 0 ;
for(int i = 1 , j = n ; i < j ; i ++ , j --)
if(s[i] != s[j]) res ++ ;
cout << res ;
return 0 ;
C. 好人 or 坏人 ?
题意:
有n个人在玩一个游戏,
这个游戏是这样的,我们将n个人分为好人和坏人,也有可能n个人都是好人或者都是坏人
好人说的话一定是对的,坏人说的话有可能对,也有可能不对。
现在给你每个人对另外一些人的判断,
问好人最多有多少个
思路:
注意到n最多有15个人,每个人要么好人要么坏人,所以暴力枚举所有可能性,时间复杂度为
2
15
2^15
215,
这里可以用状态压缩来枚举,或者用dfs枚举。
对每一种情况来说,每个人是好人还是坏人都是已知的。
那么好人说的话一定是对的,如果出现了冲突,则说明这种情况不行。
可以的话,更新一下好人人数即可。
时间复杂度:
O
(
2
15
∗
n
2
)
O(2^15*n^2)
O(215∗n2)
#include <bits/stdc++.h>
using namespace std;
int n,m,x,y,z;
vector<pair<int ,int> > a[20];
int main()
cin>>n;
for (int i=0;i<n;i++)
cin>>m;
for (int j=0;j<m;j++)
cin>>x>>y;
a[i].push_back(make_pair(x-1,y));
for (int i=0;i<1<<n;i++)
int f=1;
for (int j=0;j<n;j++)
if (i>>j&1)
for (pair<int,int>k:a[j])
if ((i>>k.first&1)!=k.second) f=0;
if (f) z=max(z,__builtin_popcount(i));
cout<<z<<endl;
return 0;
D. 异或和
题意:
给你n个数的数组
a
1
a_1
a1
a
2
a_2
a2 …
a
n
a_n
an
求(
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
(
a
[
i
]
⊕
a
[
j
]
)
\\sum_i=1^n - 1\\sum_j=i + 1^n(a[i] \\oplus a[j])
∑i=1n−1∑j=i+1n(a[i]⊕a[j])) % (
1
0
9
10^9
109 + 7)
A
⊕
B
A\\oplus B
A⊕B 表示A异或B , 也表示为(a ^ b)
思路:
位运算需要拆解每一位来看,
我们假设
b
[
k
]
[
i
]
b[k][i]
b[k][i]数组表示
a
i
a_i
ai的二进制表示下的第
k
k
k位是
1
1
1还是
0
0
0
所以我们只需要求出每一位上
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
(
b
[
k
]
[
i
]
⊕
b
[
k
]
[
j
]
)
\\sum_i=1^n - 1\\sum_j=i + 1^n(b[k][i] \\oplus b[k][j])
∑i=1n−1∑j=i+1n(b[k][i]⊕b[k][j])的值
答案累加上
2
k
∗
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
(
b
[
k
]
[
i
]
⊕
b
[
k
]
[
j
]
)
2^k * \\sum_i=1^n - 1\\sum_j=i + 1^n(b[k][i] \\oplus b[k][j])
2k∗∑i=1n−1∑j=i+1n(b[k][i]⊕b[k][j])即可
现在考虑只有一个0/1的数组,如何求 ∑ i = 1 n − 1 ∑ j = i + 1 n ( b [ k ] [ i ] ⊕ b [ k ] [ j ] ) \\sum_i=1^n - 1\\sum_j=i + 1^n(b[k][i] \\oplus b[k][j]) ∑i=1n−1∑j=i+1n(b[k][i]⊕b[k][j])
因为只有
0
/
1
0/1
0/1两种情况
偶数个
1
1
1异或等于
0
0
0
奇数个
1
1
1异或等于
1
1
1
因此
∑
i
=
1
n
−
1
∑
j
=
i
+
1
n
(
b
[
k
]
[
i
]
⊕
b
[
k
]
[
j
]
)
=
1
的
个
数
∗
0
的
个
数
\\sum_i=1^n - 1\\sum_j=i + 1^n(b[k][i] \\oplus b[k][j])=1的个数*0的个数
∑i=1n−1∑j=i+1n(b[k][i]⊕b[k][j])=1的个数∗0的个数
时间复杂度: O n l o g n Onlogn Onlogn
#include<bits/stdc++.h>
using namespace std ;
#define int long long
const int N = 1e6 + 10 , mod = 1e9 + 7 ;
int res , n , a[N] ;
signed main()
cin >> n ;
for(int i = 1 ; i <= n ; i ++)
scanf("%lld" , &a[i]) ;
for(int j = 0 ; j < 60 ; j ++)
int cnt = 0 , s ;
for(int i = 1 ; i <= n ; i ++)
if(a[i] >> j & 1) cnt ++ ;
s = cnt * (n - cnt) % mod ;
for(int i = 0 ; i < j ; i ++) s = s * 2 % mod ;
res += s , res %= mod ;
cout << res ;
return 0 ;
E. 吃菜
题意:
有n盘菜,每盘菜需要
a
i
a_i
ai的时间去吃,有
b
i
b_i
bi的美味度。
现在有如下规则:
- 点了一盘菜之后,只能将其吃完后才能点下一盘菜。
- t 时刻过后就不能再点菜了,但是依旧可以吃菜。
- 每种菜只能点一次。
最后问最后能够得到的最大美味度是多少。
思路:
如果不考虑第二条规则,很明显是个01背包问题,
我们假设
f
[
j
]
f[j]
f[j]表示时间为
j
j
j的情况下的最大美味度,
f
[
j
]
=
f
[
j
−
a
[
i
]
]
+
b
[
i
]
f[j] = f[j - a[i]] + b[i]
f[j]=f[j−a[i]]+b[i]
现在考虑加上第二条规则, 以上是关于2021-2022-2 ACM集训队每周程序设计竞赛题解的主要内容,如果未能解决你的问题,请参考以下文章 2021-2022-2 ACM集训队每周程序设计竞赛(13)题解 2021-2022-2 ACM集训队每周程序设计竞赛(13)题解 2021-2022-2 ACM集训队每周程序设计竞赛(13)题解
也就是说我们可以在
i
<
t
i < t
i<t的任意一个时刻美味度加上
b