A - 课程


题目描述

传智专修学院提供 A,B 两个课程,分别有 n,m 个学生报名。报名 A 的学生的编号为 an ,报名 B 的学生的编号为 bm,求有多少个学生同时报名了两个课程。对于所有数据,

传智杯单位换算Python 传智杯2021_acm竞赛


保证每个课程报名的学生编号不会重复。

输入格式
输入共 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 中连续子序列。

传智杯单位换算Python 传智杯2021_传智杯单位换算Python_02


输入格式

输入共 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

说明/提示

传智杯单位换算Python 传智杯2021_动态规划_03

// ***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 <bitsdc++.h>
using namespace std;
const int N=1e3+15;
typedef long long ll;
ll a[N],mp[70][70],ans[70];
ll n,m,cnt=1,x=0,f=0;

ll solve(ll k)
{
    if(k==f) {
        for(int i=1; i<=m; i++) {
            if(mp[k][i]) {
                mp[k][i]--;
                ans[k]--;
                cnt=1;f=k;x=i;
                if(ans[k]==0)  return k;
                return 0;
            }
        }
        if(ans[k]==0)  return k;
        else  return -1;
    }
    for(int i=1; i<=m; i++)
    {
        if(i>x&&mp[k][i]>=cnt)
        {
            mp[k][i]-=cnt;
            f=k;    x=i;
            ans[k]-=cnt;
            if(ans[k]==0)  return k;
            else  return -1;
        }
    }
    for(int i=1; i<=m; i++)
    {
        if(mp[k][i]>cnt)
        {
            cnt++;
            mp[k][i]-=(cnt);
            f=k;  x=i;
            ans[k]-=cnt;
            if(ans[k]==0)  return k;
            else  return -1;
        }
    }
    return 0;
}

int main()
{
    cin>>n>>m;
    ans[1]=ans[2]=ans[3]=n;
    for(int j=1; j<=3; j++) {
        for(int i=1; i<=n; i++) {
            cin>>x;
            mp[j][x]++;
        }
    }
    x=0;
    ll op=0;
    while(1) {
        op++;
        if(op>3)  op-=3;
        ll okk=solve(op);
        if(okk>0) {
            cout<<okk<<endl;
            return 0;
        }
    }
    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;
}