2024_7_15~暑期40天算法集训_个人笔记(第二周)_完成版

1.1表达式求值

NOIP2013 普及组 T2

Description

给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

Input

一行,为需要你计算的表达式,表达式中只包含数字、加法运算符 + 和乘法运算符 *,且没有括号,所有参与运算的数字均为 00 到 231−1231−1 之间的整数。

输入数据保证这一行只有 0123456789+* 这 1212 种字符。

Output

一个整数,表示这个表达式的值。

注意:当答案长度多于 44 位时,请只输出最后 44 位,前导 00 不输出。

Sample 1

InputcopyOutputcopy
1+1*3+4
8

Sample 2

InputcopyOutputcopy
1+1234567890*1
7891

Sample 3

InputcopyOutputcopy
1+1000000003*1
4

Hint

对于 30%30% 的数据,0≤0≤ 表达式中加法运算符和乘法运算符的总数 ≤100≤100。

对于 80%80% 的数据,0≤0≤ 表达式中加法运算符和乘法运算符的总数 ≤1000≤1000。

对于 100%100% 的数据,0≤0≤ 表达式中加法运算符和乘法运算符的总数 ≤100000≤100000。

分析:先进行乘法运算,再进行加法运算,可以将用于乘法运算的值存在栈里,在进行乘法运算时取出最后一位,进行运算(取模)后放回栈里,最后遍历提取栈里所有元素,以此相加,此时栈里每个元素最大位数都为4位,相加后取模得到最后结果

代码思路:

1.先读入第一个数字并放入栈中

2.读入第二个字符,如果不是'\n',循环进行,循环中再读入一个数字x

3.这个字符是+号,那么数字x入栈

4.这个字符是*号,那么出栈一个数字,与x数字相乘取模,结果重新入栈

5.最终遍历栈,结果相加取模输出.

代码:

stack<int>sta1, sta2;
int main()
{
	char c;
	int x,y;
	int ans=0;
	int sum = 0;
	scanf("%d", &x);
	sta1.push(x);
	scanf("%c", &c);
	while (c!='\n')
	{
		scanf("%d", &y);
		if (c == '+')
		{
			sta1.push(y);
		}
		else
		{
			ans = (sta1.top() * y)%10000;
			sta1.pop();
			sta1.push(ans);
		}
		scanf("%c", &c);
	}
	while (!sta1.empty())
	{
		sum = (sum+sta1.top())%10000;
		sta1.pop();
	}
	cout << sum;
	return 0;
}

1.2第 k 小整数

Description

现有 𝑛n 个正整数,要求出这 𝑛n 个正整数中的第 𝑘k 个最小整数(相同大小的整数只计算一次)。

Input

第一行为 𝑛n 和 𝑘k; 第二行开始为 𝑛n 个正整数的值,整数间用空格隔开。

Output

第𝑘k个最小整数的值;若无解,则输出 NO RESULT

Sample 1

InputcopyOutputcopy
10 3
1 3 3 7 2 5 1 2 4 6
3

Hint

𝑛≤10000n≤10000,𝑘≤1000k≤1000,正整数均小于 3000030000。

思路:把数据存在一个set(集合)里面,其自动排序去重,然后用一个迭代器找到begin,根据题目所给m的值advance(迭代器,m-1),向后迭代m-1次,找到第3个数据

知识点:advance()的用法

代码:

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++)
	{
		int x;
		cin >> x;
		mySet1.insert(x);
	}
	auto it = mySet1.begin();//迭代器指向第一个,
	if (mySet1.size() < m)
	{
		cout << "NO RESULT";
	}
	else
	{
		advance(it, m - 1);//前进m-1步
		cout << *it;
	}

	return 0;

1.3Andy's First Dictionary

题意:

输入一个文本,找出所有不同的单词(连续的字母序列),按字典序从小到大输出,单词不区分大小写。

输入输出样例

输入 #1复制

Adventures in Disneyland
Two blondes were going to Disneyland when they came to a fork in the
road. The sign read: "Disneyland Left."
So they went home.

输出 #1复制

a
adventures
blondes
came
disneyland
fork
going
home
in
left
read
road
sign
so
the
they
to
two
went
were
when

思路:一个字符一个字符输入,字符c不是EOF进入循环,判断字符isalpha(),是否是大小写字母中的一种,不是contiue,是的话循环输入c,(因为任何一段单词都是连在一起的),将字符串+=字符,循环结束时,拿到非isalpha()字符,得到单词字符串s,将s插入set里,通过set自动的将字符串按字典排序去重后,遍历输出得到答案

代码:

set<string>st1, st2, st3;//如果是字符串set(集合),他会自动将其按字典排序
int main()
{
	char ch;
	string s;
	while ((ch = getchar()) != EOF)//输入一个字符,当这个字符不等于EOF的时候
	{
		if (!isalpha(ch)) continue;//如果不是字符continue
		while (isalpha(ch))//当是字符的时候反复读入//跳出时说明当前不是字符,这个单词完毕
		{
			//保证字符是小写字符;
			ch = tolower(ch);
			s += ch;//在字符串后面加字符
			ch = getchar();
		}
		//次数字符串构建完毕,将字符串添加进
		st1.insert(s);
		s.clear();//清空字符串
	}
	//次数st1自动按照字典排序,遍历输出
	for (auto it = st1.begin(); it != st1.end(); it++)
	{
		cout << *it << endl;
	}
	return 0;
};

1.4

小明爱集合

最近小明又喜欢上了集合,于是他提出了很多有关集合的问题,其中的一个问题是给你两个集合(集合内部没有重复的元素),让你求集合的相似度是多少,集合的相似度定义如下:

22 个集合的相似度 = 相同元素的个数/(相同元素个数+不同元素个数)

聪明的你可以帮助小明解决这个问题吗?

Input

题目含有多组数据,第一行一个数 𝑇T ,表示数据的组数;
对于每组数据:
第一行包括两个数 𝑛,𝑚n,m ,分别表示两个集合元素的个数 (1≤𝑛,𝑚<100000)(1≤n,m<100000) ;
第二行 𝑛n 个数表示前一集合的 𝑛n 个数,以空格隔开;
第三行 𝑚m 个数表示后一集合的 𝑚m 个数,以空格隔开;
其中对于两集合中任意数 𝑎𝑖ai ,有 0≤𝑎𝑖≤𝑚𝑎𝑥(2×𝑛,2×𝑚)0≤ai≤max(2×n,2×m) 。

Output

对于每组数据,输出两个集合的相似度,输出结果乘 100100 后取整数部分。

Data Description

对于 10%10% 的数据, 1≤𝑇≤21≤T≤2 , 𝑛,𝑚≤4n,m≤4
对于 50%50% 的数据, 1≤𝑇≤41≤T≤4 , 𝑛,𝑚≤1024n,m≤1024
对于 100%100% 的数据, 1≤𝑇≤101≤T≤10 , 𝑛,𝑚≤100000(0≤𝑎𝑖≤𝑚𝑎𝑥(2×𝑛,2×𝑚))n,m≤100000(0≤ai≤max(2×n,2×m))

Sample 1

InputcopyOutputcopy
2
2 3
1 2 
2 3 4
3 3
5 3 4
3 4 1
25
50

思路:将数据放入set里面去重,得到去重之后长度,然后根据题意中的数学公式算出答案.

注意:cin>>和cout<<会导致超时,写之前要加上ios::sync_with_stdio(false);

代码:

using namespace std;
set<int>st1, st2, st3;
int main()
{
	int T;
	ios::sync_with_stdio(false);
	cin >> T;
	for (int i = 0; i < T; i++)
	{
		int n, m;
		int flag1 = 0, flag2 = 0;
		cin >> n >> m;
		for (int j = 0; j < n; j++)
		{
			int x;
			cin >> x;
			flag1++;
			st3.insert(x);
		}
		for (int j = 0; j < m; j++)
		{
			int x;
			cin >> x;
			flag2++;
			st3.insert(x);
		}
		int a = flag1;
		int b = flag2;
		int c = st3.size();
		double ans = (a + b - c) * 1.0 / (c);
		cout << (int)(ans * 100) << endl;
		st3.clear();
	}
	return 0;
};

1.5学籍管理

Description

您要设计一个学籍管理系统,最开始学籍数据是空的,然后该系统能够支持下面的操作(不超过 105105 条):

  • 插入与修改,格式1 NAME SCORE:在系统中插入姓名为 NAME(由字母和数字组成不超过 20 个字符的字符串,区分大小写) ,分数为 SCORESCORE(0<SCORE<2310<SCORE<231) 的学生。如果已经有同名的学生则更新这名学生的成绩为 SCORE。如果成功插入或者修改则输出OK
  • 查询,格式2 NAME:在系统中查询姓名为 NAME 的学生的成绩。如果没能找到这名学生则输出Not found,否则输出该生成绩。
  • 删除,格式3 NAME:在系统中删除姓名为 NAME 的学生信息。如果没能找到这名学生则输出Not found,否则输出Deleted successfully
  • 汇总,格式4:输出系统中学生数量。

Sample 1

InputcopyOutputcopy
5
1 lxl 10
2 lxl
3 lxl
2 lxl
4

知识点:考察map增删改查常用函数功能的用法

代码

nt main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		int x;
		cin >> x;
		if (x == 1)
		{
			string name;
			int grade;
			cin >> name >> grade;
			myMap[name] = grade;//直接插入,如果存在创建,不存在修改
			cout << "OK" << endl;
		}
		else if (x == 2)
		{
			string name;
			cin >> name;
			auto it = myMap.find(name);//通过钥匙,找钥匙和门这一对,返回迭代器(指针),他指向的就是这一对;
			//判断it有没有找到
			if (it != myMap.end())//找到了
			{
				cout << it->second << endl;
			}
			else//没找到
			{
				cout << "Not found" << endl;
			}
		}
		else if (x == 3)//删除,根据钥匙删除这一对数据//删除之前要确保这个元素存在,先find一下看看有没有
		{
			string name;
			cin >> name;
			auto it = myMap.find(name);//找到这一对
			if (it != myMap.end())//找到了
			{
				myMap.erase(name);//通过钥匙删除这一对
				cout << "Deleted successfully" << endl;
			}
			else//没找到
			{
				cout << "Not found" << endl;
			}
		}
		else//统计现在map里面的对数
		{
			int ans = myMap.size();
			cout << ans << endl;
		}
	}
	return 0;
}

 1.6Cities and States S

Description

Farmer John 有若干头奶牛。为了训练奶牛们的智力,Farmer John 在谷仓的墙上放了一张美国地图。地图上表明了每个城市及其所在州的代码(前两位大写字母)。

由于奶牛在谷仓里花了很多时间看这张地图,他们开始注意到一些奇怪的关系。例如,FLINT 的前两个字母就是 MIAMI 所在的 FL 州,MIAMI 的前两个字母则是 FLINT 所在的 MI 州。
确切地说,对于两个城市,它们的前两个字母互为对方所在州的名称。

我们称两个城市是一个一对「特殊」的城市,如果他们具有上面的特性,并且来自不同的州。对于总共 𝑁N 座城市,奶牛想知道有多少对「特殊」的城市存在。请帮助他们解决这个有趣的地理难题!

Input

输入共 𝑁+1N+1 行。

第一行一个正整数 𝑁N,表示地图上的城市的个数。
接下来 𝑁N 行,每行两个字符串,分别表示一个城市的名称(2∼102∼10 个大写字母)和所在州的代码(22 个大写字母)。同一个州内不会有两个同名的城市。

Output

输出共一行一个整数,代表特殊的城市对数。

Sample 1

InputcopyOutputcopy
6
MIAMI FL
DALLAS TX
FLINT MI
CLEMSON SC
BOSTON MA
ORLANDO FL
1

Hint

数据规模与约定

对于 100%100% 的数据,1≤𝑁≤2×1051≤N≤2×105,城市名称长度不超过 1010。

分析题目:输出两个字符串,第一个字符串只需要前两位

思路:应用map<string, int> box;将每次的字符串进行反向拼接,以新的例如MIFL字符串为钥匙,构建类似哈希表的结构,下一个其反向数据应用map查阅哈希表,可以得到数据,次数++.

注意:特判a!=b时,因为不存在两个相同的州,a==b时不应该计数,

代码:

using namespace std;
int n, ans;
string a, b;
map<string, int> box;
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{

		cin >> a >> b;
		a = a.substr(0, 2);
		if (a != b)
		{
			ans += box[a + b];
			box[b + a]++;
		}

	}
	cout << ans << endl;
	return 0;

1.7P1102 A-B 数对

题目描述

给出一串正整数数列以及一个正整数 𝐶C,要求计算出所有满足 𝐴−𝐵=𝐶A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入格式

输入共两行。

第一行,两个正整数 𝑁,𝐶N,C。

第二行,𝑁N 个正整数,作为要求处理的那串数。

输出格式

一行,表示该串正整数中包含的满足 𝐴−𝐵=𝐶A−B=C 的数对的个数。

输入输出样例

输入 #1复制

4 1
1 1 2 3

输出 #1复制

3

说明/提示

对于 75%75% 的数据,1≤𝑁≤20001≤N≤2000。

对于 100%100% 的数据,1≤𝑁≤2×1051≤N≤2×105,0≤𝑎𝑖<2300≤ai​<230,1≤𝐶<2301≤C<230。

2017/4/29 新添数据两组

思路:将A-B=C转换成A-C=B,将所有数据存在数组里,将数据的数量存在map里,遍历数组得到一系列b的取值,看看真实序列中是否存在b,如果存在结果加上b的数量.

注意:二重循环O(n*n)超时,用哈希表可以直接找到数据,变成O(n),此题要求用long long存数据,只有一个测试数据过不来很可能是没把int换成long long,

代码:
 

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	ll n, m;
	cin >> n>>m;
	for (int i = 0; i < n; i++)
	{
		ll x;
		cin >> x;
		a.push_back(x);
		mapp[x]++;
	}
	ll num = 0;
	for (int i = 0; i < n; i++)
	{
		ll b = a[i] - m;
		if (mapp.find(b) != mapp.end())//说明b在mapp里,有配对
		{
			num += mapp[b];
		}
	}
	cout << num;
	return 0;
};

1.8

A - 学长喜欢拆分

 洛谷 - U384102 

给定一个整数𝑛n要求你拆分成𝑥∗𝑦+𝑥+𝑦=𝑛x∗y+x+y=n,请问是否有这种情况,如果有输出𝑌𝐸𝑆YES,反之输出𝑁𝑂NO;

需要保证的是𝑥,𝑦x,y是正整数!

Input

输入一个𝑛(1<=𝑛<=2∗109)n(1<=n<=2∗109)

Output

输出𝑌𝐸𝑆YES或者𝑁𝑂NO

Sample 1

InputcopyOutputcopy
2
NO

Sample 2

InputcopyOutputcopy
3
YES

Hint

33可以拆成1∗1+1+11∗1+1+1的形式

思路:若是用二重循环先枚举x从1到n,再枚举y从1到n判断等不等于n会超时,这道题可以根据n用i从1遍历到sqrt(n),判断i是不是能被n整除,如果是,i就是n的一个因数,(n/i)是n的另一个因数,判断两个因数是否全部满足题意是正整数即可.

代码:

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	int n;
	cin >> n;
	n += 1;
	int flag = 0;
	for (int i = 1; i <= sqrt(n); i++)
	{
		if (n % i == 0 && (i - 1) > 0)
		{
			if (((n / i) - 1) > 0)
			{
				flag = 1;
				cout << "YES";
				break;
			}
		}
	}
	if (flag == 0)
	{
		cout << "NO";
	}
	return 0;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值