湖南工学院2021级ACM正式队员第二次周测题解

问题A 事不过三

给定长度为 n 的数组 ai 询问数组是否存在某一数字出现的次数大于等于 3,由于数字很小 ai < 2e5 所以我们用 vis 数组标记次数即可 下标即代表值。若不存在 ai 的大小限制 我们可以使用map记录效果相同。

#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
int vis[N];
void solve()
{
    int n;
    cin >> n;
    int ans = -1;
    for(int i=1;i<=n;i++)vis[i] = 0;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin >> x;
        vis[x] ++;
        if(vis[x] >= 3)ans = x;
    }
    cout << ans << endl;
    return ;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}

问题B 奇偶数

题意:

给定长度为 n的数组 可以对偶数下标的或奇数下标的数全部加1并不限操作次数 询问是否能使数组中所有数奇偶一致。

思路:

因为每次操作必须对全部偶数或奇数下标的数进行,所以对于下标奇偶相同的数来说每次变化是同步变化的,如果初始不同那么就不可能通过操作来使之相同。例如:1 2 2下标为1 3的数初始奇偶不同,对偶数下标操作对1 3下标无影响,对奇数下标操作也只能同时变化奇偶。于是判断一下是否初始数组奇数下标数/偶数下标数奇偶是否相同即可。

#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 110;
int a[N];
void solve()
{
    int n;
    cin >> n;
    bool F = true;
    for(int i=1;i<=n;i++)
    {
        cin >> a[i];
        if((i&1)&&a[i]%2!=a[1]%2)F = false;
        else if(i%2==0 && a[i]%2!=a[2]%2)F = false ;
    }
    if(F) cout << "YES" << endl;
    else cout << "NO" << endl;
    return ;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}

问题C 坠落

模拟石头掉落的过程即可,因为列与列之间互不影响 我们可以对每一列单独模拟

#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 110;
char a[N][N];
void solve()
{
    int n,m;
    cin >> n >> m;
    for(int i=1;i<=n;i++)scanf("%s",a[i] + 1);
    for(int i=1;i<=m;i++)//从列开始
    {
        for(int j=n,up=j;j>=1;up=j,j--)
        {
            if(a[j][i]=='o') continue ;

            int sum = 0;
            up = j;
            if(a[j][i]=='*')sum = 1;
            while(up - 1 >= 1 && a[up - 1][i]!='o')
            {
                up --;
                if(a[up][i]=='*')sum ++;
            }
            for(int k=0;k<sum;k++) a[j-k][i] = '*';
            for(int k=j-sum;k>=up;k--) a[k][i] = '.';
            j = up;
        }
    }
    for(int i=1;i<=n;i++)printf("%s\n",a[i] + 1);
    return ;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}

问题D 吃糖果

题意:

给定 n 颗糖果重量为 ai 。kk只能从左往右吃,mz只能从右往左吃,并且不能跳过不吃当前糖果去吃后面的。要求kk和mz吃到糖果重量一样,询问两人最多能吃到多少糖果。

思路:

只能向一个方向吃糖果,并且一个从左一个从右,那么我们可以使用双指针,分别记录kk和mz的糖果重量,如果相同就更新答案,否则谁更小谁就接着吃糖果。

#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 998244353;
using namespace std;
ll a[300000];
int main() {
    int t;
    cin >> t;
    while(t--){
    	int n;
    	cin >> n;
    	for(int i =1;i<=n;i++){
    		cin >> a[i];
		}
		int ans =0;
		int l = 1,r = n;
		ll x = 0,y = 0; 
		while(l<=r){
			if(x<y){
				x+=a[l++];
			}else{
				y+=a[r--];
			}
			if(x==y){
				ans = l-1+n-r;
				x+=a[l++];
			}
			//cout << l << " " << r <<endl;
		}
		cout << ans << endl;
	}
	return 0;
}

问题E 真的②

题意:

给定 n个长度为2的字符串,询问有多少个字符串对 ( i , j ) i < j 满足 i 字符串与 j 字符串有且仅有一个字符不同。

思路:

因为字符串长度为2,我们可以直接用数组 a 记录各种字符串的数量,对于每个字符串我们当某一位不相同时才做ans的更新,由于字母仅为a-k,所以直接枚举这个范围即可。标程用了j<=26(只是因为懒得数a-k有多少字符了...多写一点无所谓不影响结果)。

#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 998244353;
using namespace std;
ll a[30][30];
int main() {
    int t;
    cin >> t;
    while(t--){
    	memset(a,0,sizeof(a));
    	int n;
    	cin >> n;
    	ll ans = 0;
    	for(int i =1;i<=n;i++){
    		string b;
    		cin >> b;
    		a[b[0]-'a'+1][b[1]-'a'+1]++;
    		for(int j = 1;j<=26;j++){
    			int x1 = b[0]-'a'+1,x2=b[1]-'a'+1;
    			if(j!=x1){
    				ans+=a[j][x2];
				}
				if(j!=x2){
					ans+=a[x1][j];
				}
			}
		}
		cout << ans<<endl;
	}
	return 0;
}













 

问题F 最大 &

题意:

给定长度为 n的数组 a 有 k次操作机会。可以使任意 ai | 2^j(j<=30)询问进行k次操作后将  a1 AND a2 AND … AND an后的最大值是多少。

思路:

因为二进制数 AND 操作不同数位之间没影响 ,最后得到的答案二进制位上如果是1要求所有的 ai二进制该数位上为1 于是我们贪心的从二进制的高位开始遍历数组,若 ai 该位上为0那么计数sum ++将 a1->an 统计完后若小于等于 k 说明该二进制数位可以通过若干操作使得全部 ai 为1 答案加上该二进制数位代表的值,同时 k - sum

#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 2e5 + 10;
ll a[N],b[40],n,k;
void init()
{
    b[0] = 1;
    for(int i=1;i<=30;i++)b[i] = b[i-1] << 1;//预处理好二进制数位的值
}
void solve()
{
    cin >> n >> k;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    ll ans = 0;
    for(int i=30;i>=0;i--)
    {
        int sum = 0;
        for(int j=1;j<=n;j++)
        {
            if(!(a[j]>>i&1)) sum ++;//位运算判断该位上二进制数位是否为1
        }
        if(k >= sum)
        {
            ans += b[i];
            k -= sum;
        }
    }
    printf("%lld\n",ans);
    return ;
}
int main()
{
    int T;
    init();
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}

最后

本套题目难度不大,是某网站最低难度的一场比赛,原比赛是8题,另外两题过于简单,就不放出来了。原比赛赛时共3.5w人参与,近4000人AK,说明难度还是相当低的。本次赛时未做出来的题希望各位同学在经过自己的思考后去尝试做一下,实在做不出来再看题解或请教他人。本场的题建议赛后补完,毕竟没有什么高难度的算法,只是一些基础的运用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值