1.1表达式求值
NOIP2013 普及组 T2
Description
给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。
Input
一行,为需要你计算的表达式,表达式中只包含数字、加法运算符 +
和乘法运算符 *
,且没有括号,所有参与运算的数字均为 00 到 231−1231−1 之间的整数。
输入数据保证这一行只有 0123456789+*
这 1212 种字符。
Output
一个整数,表示这个表达式的值。
注意:当答案长度多于 44 位时,请只输出最后 44 位,前导 00 不输出。
Sample 1
Inputcopy | Outputcopy |
---|---|
1+1*3+4 | 8 |
Sample 2
Inputcopy | Outputcopy |
---|---|
1+1234567890*1 | 7891 |
Sample 3
Inputcopy | Outputcopy |
---|---|
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
Inputcopy | Outputcopy |
---|---|
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
Inputcopy | Outputcopy |
---|---|
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
Inputcopy | Outputcopy |
---|---|
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
Inputcopy | Outputcopy |
---|---|
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 - 学长喜欢拆分
给定一个整数𝑛n要求你拆分成𝑥∗𝑦+𝑥+𝑦=𝑛x∗y+x+y=n,请问是否有这种情况,如果有输出𝑌𝐸𝑆YES,反之输出𝑁𝑂NO;
需要保证的是𝑥,𝑦x,y是正整数!
Input
输入一个𝑛(1<=𝑛<=2∗109)n(1<=n<=2∗109)
Output
输出𝑌𝐸𝑆YES或者𝑁𝑂NO
Sample 1
Inputcopy | Outputcopy |
---|---|
2 | NO |
Sample 2
Inputcopy | Outputcopy |
---|---|
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;
};