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(215n2)

#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=1n1j=i+1n(a[i]a[j])) % ( 1 0 9 10^9 109 + 7)
A ⊕ B A\\oplus B AB 表示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=1n1j=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]) 2ki=1n1j=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=1n1j=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=1n1j=i+1n(b[k][i]b[k][j])=10

时间复杂度 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[ja[i]]+b[i]

现在考虑加上第二条规则,
也就是说我们可以 i < t i < t i<t的任意一个时刻美味度加上 b

以上是关于2021-2022-2 ACM集训队每周程序设计竞赛题解的主要内容,如果未能解决你的问题,请参考以下文章

2021-2022-2 ACM集训队每周程序设计竞赛题解

2021-2022-2 ACM集训队每周程序设计竞赛(13)题解

2021-2022-2 ACM集训队每周程序设计竞赛(13)题解

2021-2022-2 ACM集训队每周程序设计竞赛(13)题解

2021-2022-2 ACM集训队每周程序设计竞赛 - 问题 C:回到学校 - 题解

2021-2022-2 ACM集训队每周程序设计竞赛(10) - 问题 C: 下一个素数 - 题解