2021第三届传智杯决赛全题解

A - 课程

题目描述
传智专修学院提供 A,B 两个课程,分别有 n,m 个学生报名。报名 A 的学生的编号为 an ,报名 B 的学生的编号为 bm,求有多少个学生同时报名了两个课程。对于所有数据,
n,m,a_i,b_i\leq 20n,m,a
保证每个课程报名的学生编号不会重复。

输入格式
输入共 3 行。
第 1 行输入 2 个正整数 n,m。
第 2 行输入 n 个正整数 a1…an,表示报名课程 A 的学生编号。
第 3 行输入 m 个正整数 b1…bm,表示报名课程 B 的学生编号。
输出格式
输出共 1 行 1 个整数,表示答案。

输入 #1
5 5
1 2 3 4 5
1 3 4 5 6
输出 #1
4

说明/提示
样例解释

我们发现,1,3,4,5 这 4 名学生同时报名了两门课程,所以答案是 4。

思路:数据不大,可以直接暴力,二重循环判断即可。数据大的话应该可以采用 “双指针” 算法。

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
int n,m,a[99],b[99],sum;

int main()
{
    
    
	cin>>n>>m;
	for(int i=1; i<=n; i++) cin>>a[i];
	for(int i=1; i<=n; i++) cin>>b[i]; 
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=m; j++)
		if(a[i]==b[j])  sum++;
	}
	cout<<sum<<endl;
	return 0;
}

B - 序列

题目描述
传智专修学院有 n 名同学,每个同学都有一个数字 an 。同时还知道一个常数 k 。如果有两名同学,第 i 名同学和第 j 名同学,满足 i<j 且 ai x aj ≤ k,那么这两名同学就被称为“和谐的一对”。请问这些同学中,有多少对“和谐的一对”呢?
对于所有数据,n<=1e3,ai<=1e5,k<=1e9。

输入格式
输入共 2 行。
第 1 行输入两个正整数 n,k。
第 2 行输入 n 个正整数 a1…an。
输出格式
输出共 1 行 1 个整数,表示答案。

输入 #1
5 5
1 2 3 4 5
输出 #1
4

说明/提示
样例解释

样例中,(1,2),(1,3),(1,4),(1,5) 这 4 对都是“和谐的一对”。

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
ll n,a[1010],sum,k;

int main()
{
    
    
	cin>>n;
	scanf("%lld",&k);
	for(int i=1; i<=n; i++)  cin>>a[i];
	for(int i=1; i<n; i++) {
    
    
		for(int j=i+1; j<=n; j++) {
    
    
			if(a[i]*a[j]<=k)  sum++;
		}
	}
	cout<<sum<<endl;
	return 0;
}

C - 子串


题目描述
在传智的开发课堂上,希望您开发一款文档处理软件。给定 T 组询问,每次给定 2 个长度为 n,m 的只含英文字母的字符串 a,b,求 a 在 b 中的出现次数,相同字符不区分大小写。注意 a 是 b 中连续子序列。
在这里插入图片描述
输入格式
输入共 3T+1 行。
第 1 行输入 1 个正整数 T。
接下来共 T 组输入,每组输入共 3 行。
第 1 行输入 2 个正整数 n,m。
第 2 行输入一个长度为 n 的字符串 a。
第 3 行输入一个长度为 m 的字符串 b。
输出格式
输出共 T 行,第 i 行输出 1 个整数,表示询问 i 的答案。

输入 #1
5
3 10
abc
abcabcabca
2 10
aa
AAaAaaAaAa
5 5
AbCdE
eDcBa
5 5
abcde
ABCDE
3 10
aba
ABaBaAbaBA
输出 #1
3
9
0
1
4

说明/提示
在这里插入图片描述

// ***KMP算法***
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+1000;
int n,m;
char a[N],b[N];
int f[N];
void init()
{
    
    
	for(int i=1;i<=n;i++)
	if(a[i]>='A'&&a[i]<='Z')
	a[i]=a[i]+'a'-'A';
	for(int i=1;i<=m;i++)
	if(b[i]>='A'&&b[i]<='Z')
	b[i]=b[i]+'a'-'A';
    for(int i=2,j=0;i<=n;i++)
    {
    
    
        while(j&&a[i]!=a[j+1]) j=f[j];
        if(a[i]==a[j+1]) j++;
        f[i]=j;
    }
}
int main()
{
    
    
	int T;
	cin>>T;
	while(T--)
	{
    
    
        cin>>n>>m>>a+1>>b+1;
        init();
        int cnt=0;
        for(int i=1,j=0;i<=m;i++)
        {
    
    
            while(j&&b[i]!=a[j+1])  j=f[j];
            if(b[i]==a[j+1]) j++;
            if(j==n)
            {
    
    
                cnt++;
                j=f[j];
            }
         }
         cout<<cnt<<endl;
    }
    return 0;
}

D - 打牌

题目描述
三名同学在学习编程的休息时间(编号 1,2,3)打扑克,每人一开始 n 张牌,牌一共 m 种,若干张相同的牌可以一起出。一开始由第一个人出,打出自己的牌里最小的牌。接下来,以玩家 1,2,3,… 的顺序轮流出牌,每人打出一组比上个人打出的牌大的,自己能打出的最小的牌,若没有则跳过。牌的大小是这么决定的:一组张数多的牌比张数少的牌大,如果张数同样多,那么点数大的牌比较大。例如,(1,1,1)>(3,3)>(2,2)>(4)>(1)。若一轮中,其余两个人都无法打出牌,则重新下次由打出最后一张牌的人开始打。谁最先打完所有的牌,谁就赢了。请问最后谁会胜利呢?输出胜者的编号。
对于所有数据,n,m≤50。

输入格式
输入共 4 行。
第 1 行输入 2 个正整数 n,m。
第 2 到 4 行,每行输入 n 个数,表示每个人一开始的牌。
输出格式
输入共 1 行 1 个正整数,表示胜者的编号。

输入 #1
10 3
1 3 3 1 3 3 1 2 3 3
3 2 1 2 2 3 3 1 1 2
2 2 1 2 3 1 2 3 3 1
输出 #1
3

说明/提示
样例中的玩法

第 1 回合:
【1】:1 3 3 1 3 3 1 2 3 3,打出 [1]
【2】:3 2 1 2 2 3 3 1 1 2,打出 [2]
【3】;2 2 1 2 3 1 2 3 3 1,打出 [3]
【1】:3 3 1 3 3 1 2 3 3,打出 [1,1]
【2】:3 1 2 2 3 3 1 1 2,打出 [2,2]
【3】;2 2 1 2 1 2 3 3 1,打出 [3,3]
【1】:3 3 3 3 2 3 3,打出 [3,3,3]
【2】:3 1 3 3 1 1 2,出不起
【3】;2 2 1 2 1 2 1,打出 [2,2,2,2]
【1】:3 2 3 3,出不起
【2】:3 1 3 3 1 1 2,出不起

第 2 回合:
【3】;1 1 1,打出 [1]
【1】:3 2 3 3,打出 [2]
【2】:1 3 3 1 1 2,打出 [3]
【3】;1 1,打出 [1,1] <- 获胜

// ***大模拟***
#include <bits/stdc++.h>
using namespace std;
const int N=4e5+10;
typedef long long LL;
typedef pair<LL,LL> PLL;
int n,m;

struct f{
    
    
	int x,y;
}s[N];

int check1(int u)
{
    
    
	int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
	for(int i=1; i<=m; i++)
	{
    
    
		if(s[i].x==s[u].x)  cnt1++;
		if(s[i].y==s[u].y)  cnt2++;
		if(s[i].x-s[u].x==s[i].y-s[u].y)  cnt3++;
		if(s[u].x-s[i].x==s[i].y-s[u].y)  cnt4++;
	}
	int res;
	res=max(cnt1,cnt2);
	res=max(res,cnt3);
	res=max(res,cnt4);
	return res;
}

int check2(int u)
{
    
    
	int cnt=0;
	int lx=s[u].x-n,rx=s[u].x+n,ly=s[u].y-n,ry=s[u].y+n;
	for(int i=1; i<=m; i++)
	    if(s[i].x<=rx&&s[i].x>=lx&&s[i].y<=ry&&s[i].y>=ly)
	        cnt++;
	return cnt;
}

int main()
{
    
    
	cin>>n>>m;
	for(int i=1; i<=m; i++)
	{
    
    
		int a,b;
		cin >> a >> b;
		s[i]={
    
    a,b};
	}
	int ans=0;
	for(int i=1; i<=m; i++)
	{
    
    
		int t = max(check1(i),check2(i));
		ans = max(ans,i);
	}
	cout << ans << endl;
	return 0;
}

E - 商店


题目描述
有 n 名同学去逛商店,店里有 m 个物品,第 i 人有 wi 块钱,第 i 个物品价格 ci 元。每个人至多买一个物品,每个物品只能被买一次,问最多有多少人能买到物品。对于所有数据,n,m<=1e5,wi,ci<=1e9。

输入格式
输入共 3 行。
第 1 行输入 2 个正整数 n,m。
第 2 行输入 n 个整数 w1…wn,wi 表示第 i 人的钱。
第 3 行输入 m 个整数 c1…cm,ci 表示第 i 个物品的价格。
输出格式
对于所有数据,n,m<=1e5,wi,ci<=1e9。

输入 #1
15 20
4 3 9 10 7 7 5 3 6 1 8 6 6 1 5
12 4 1 9 8 5 8 6 4 5 18 8 14 9 9 7 20 11 8 19
输出 #1
10

思路:排序,从最小的开始,买的起就下一个,然后break;买不起,直接break。

#include <bits/stdc++.h>
#define ll long long 
using namespace std;
const int N = 1e5+10;
ll n,m,w[N],c[N],sum;

int main()
{
    
    
	cin>>n>>m;
	for(int i=1; i<=n; i++)  cin>>w[i];
	for(int i=1; i<=m; i++)  cin>>c[i];
	sort(w+1,w+1+n);
	sort(c+1,c+1+m);
	for(int i=1,j=1; i<=n; i++)
	{
    
    
		if(w[i]>=c[j])
		{
    
    
			sum++;
			j++;
		}
	} 
	printf("%lld",sum);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Luoxiaobaia/article/details/115285263