前言
这周与上周四五全是STL,学完就用,真的我谢谢你。
A-演唱会
Description
一个特殊的节日,zyl 举办了一场演唱会,他想要规划一下演唱会的曲目。
根据同学的要求,他要从 n 首歌(编号 1∼n)中选出 m 首加入演唱会歌单。
选择的规则很简单,班上有 a 名学生(不包括 zyl),学号为 1∼a。zyl 会按照学号统计每位同学从每首歌中得到的快乐值,记为 hi,j。一首歌的「欢乐度」是它所给予其他所有同学的「快乐值」总和。
巧妙的是,由于歌曲风格迥异,同一个学生一定会从不同的歌中会收获不同的快乐值,且不会有任何两首歌的欢乐度相同。
zyl 选出欢乐度最高的 m 首歌,并将它们按欢乐度从大到小排好序。
但 zyl 注意到了她的快乐值…
无论如何,zyl 一定会把她最喜欢的歌放进歌单(她获得快乐值最高的歌即为她最喜欢的歌)!
如果她最喜欢的歌之前已经在歌单中,那么 zyl 会把这首歌提到歌单的第一个位置(即,仅将该歌曲的位置变为第一位,其余歌曲的相对位置不变);但如果不在,zyl 则会把已经选择好的歌单里的最后一首歌给删掉。然后把她最喜欢的曲目放在歌单的最后。
现在 zyl 将统计的快乐值数据和她的学号交给你,请你帮他列出演唱会的歌单。
Input
输入共 a+1 行。
第一行共四个整数 n,m,a,b,分别代表待选的歌的数量,需要选出的歌的数量,班上的人数,她的学号。
接下来 a 行,每行 n 个整数,第 i+1 行第 j 个数代表学号为 i 的学生从第 j 首歌收获的快乐值 hi,j。
Output
输出共一行用空格隔开的 m 个整数,依次代表演唱会的歌单上的歌的编号。
Sample 1
Inputcopy | Outputcopy |
---|---|
4 2 3 2 2 4 3 1 1 2 3 4 2 3 4 1 | 3 4 |
Hint
样例 1 解释
按照欢乐度排序后靠前的两道是 3,23,2,但由于她最喜欢的歌是 44,不在歌单里,于是将 22 从歌单里删除,之后将 44 放在最后。最后的歌单为 3,43,4。
数据规模与约定
对于 100%100% 的数据,1≤m≤n≤10^5,1≤b≤a≤100。0≤ℎ≤10^6,0≤hi,j≤10^6。
测试点编号 | n | m | a | hi,j |
---|---|---|---|---|
1∼21∼2 | ≤5≤5 | =1=1 | ≤5≤5 | ≤10000≤10000 |
3∼43∼4 | ≤1000≤1000 | =n | ≤100≤100 | ≤10000≤10000 |
5∼65∼6 | ≤1000≤1000 | ≤1000≤1000 | =1=1 | ≤10000≤10000 |
7∼97∼9 | ≤1000≤1000 | ≤1000≤1000 | ≤100≤100 | ≤10000≤10000 |
1010 | ≤105≤105 | ≤105≤105 | ≤100≤100 | ≤106≤106 |
详解
#include<bits/stdc++.h>
using namespace std;
struct song{
int id,k;
}h[100005];
bool cmp(song a,song b){
return a.k>b.k;
}
int main()
{
int n,m,a,b;
int max=0,max1=0;
scanf("%d %d %d %d",&n,&m,&a,&b);
for(int i=1;i<=a;i++){
for(int j=1;j<=n;j++){
h[j].id=j;
int x;
scanf("%d",&x);
if(i==b){
if(x>max){
max=x;
max1=j;
}
}
h[j].k+=x;
}
}
sort(h+1,h+n+1,cmp);
int ret=0;
for(int i=1;i<=m;i++){
if(h[i].id==max1){
ret=1;
break;
}
}
if(ret==1){
printf("%d",max1);
for(int i=1;i<=m;i++){
if(h[i].id!=max1)
printf(" %d",h[i].id);
}
}
else{
for(int i=1;i<m;i++){
printf("%d ",h[i].id);
}
printf("%d",max1);
}
}
思路步骤
1.记录每首歌的欢迎值的和与zyl的;
2.排序;
3.zyl喜欢的是否在前m个(ret=0/1);
4.分情况输出。
个人问题(上榜原因)
1.最经典的struct;
2.较难落实思路(结构体的普遍问题)
B-狼人杀
“狼人杀”的原型是上世纪八十年代末,莫斯科大学心理学系的迪米特里·达维多夫发明了一种警察与杀手互猜身份的游戏,也就是“杀人游戏”。“杀人游戏”从一开始就只有核心规则得到了确定,本身是一款开源游戏。1990年以后,“杀人游戏”逐渐传播到了欧洲,随后到了美国,在每个不同的国家和地区都根据各自文化背景“演化”出了新的内容。
大哲是一个忠实的狼人杀爱好者,而且是高手中的高手。由于她过于擅长各类套路,并且具备敏锐的直觉与极强的心理素质,甚至还是一个心理学博士,她的朋友逐渐失去了游戏体验。为了照顾她的朋友,她决定制定一种不靠计谋、不用推理,全靠强运的“杀法”:
游戏玩家围成一个圈,从指定的第一个人开始数数,数到第 m 个人时,那个人就会被处死。之后从被处死的人的后一个人开始数数,再数到第 m 个人处死......依此方法不断杀死玩家。假如说玩家有好人与坏人两种身份,每种身份各 n 人,试问如何安排这些人的座位,能使得在处死 n 人后,剩下的 n 人都是好人
Input
多组数据,每组数据输入:好人和坏人的人数n(<=32767)、步长m(<=32767);
Output
对于每一组数据,输出2n个大写字母,‘G’表示好人,‘B’表示坏人,50个字母为一行,不允许出现空白字符。相邻两组输出之间有一个空行隔开。
Sample
Inputcopy | Outputcopy |
---|---|
2 3 2 4 | GBBG BGGB |
详解
#include<bits/stdc++.h>
using namespace std;
int n,m;
char x[70000];
int main()
{
while(cin>>n>>m)
{
int k=0,f=0;
for( int i=0;i<2*n;i++)
x[i]='G';//全好
for( int i=0;;i++){
if(i==2*n) i=0;//循环
if(x[i]!='B') k++;//杀过的人数的时候忽略
if(x[i]!='B'&&k==m){//没被杀并且刚好是第m个
f++;//
x[i]='B';//
k=0;//重新数
}
if(f==n) break;
}
for(int i=0;i<2*n;i++){
cout<<x[i];
if(i!=2*n-1&&(i+1)%50==0) cout<<endl;
}
cout<<endl<<endl;
}
return 0;
}
思路步骤
1.挑坏人杀(B),先全赋值为好。
2.跳过杀过的;
3.确定符合条件(K,还是G);
4.坏人+1;
5.循环到F=N;
个人问题(上榜原因)
1.最经典的约瑟夫环;
2.卡了1小时看了七八种题解才解决。
C-中位数
Description
给定一个长度为 N 的非负整数序列 A,对于前奇数项求中位数。
Input
第一行一个正整数 N。
第二行 N 个正整数A 1…N。
Output
共 ⌊2N+1⌋ 行,第 i 行为 A1…2i−1 的中位数。
Sample 1
Inputcopy | Outputcopy |
---|---|
7 1 3 5 7 9 11 6 | 1 3 5 6 |
Sample 2
Inputcopy | Outputcopy |
---|---|
7 3 1 5 9 8 7 6 | 3 3 5 6 |
Hint
对于 20%20% 的数据,N≤100;
对于 40%40% 的数据,N≤3000;
对于 100%100% 的数据,1≤N≤1000000≤Ai≤1^09。
详解
#include<bits/stdc++.h>
using namespace std;
int main(){
priority_queue<int> max;
priority_queue<int,vector<int>,greater<int> > min;
int i,n,num,mid;
cin>>n;
cin>>num;
mid=num; cout<<mid<<endl;
for(i=2;i<=n;i++){
cin>>num;
if(num>mid) min.push(num);
else max.push(num);
if(i%2){
while(max.size()!=min.size())
if(max.size()>min.size()){
min.push(mid);
mid=max.top();
max.pop();
}
else{
max.push(mid);
mid=min.top();
min.pop();
}
cout<<mid<<endl;
}
}
}
思路步骤
1.第一个无脑中位数;
2.比大小放入队列queue;
3.输入2次(偶次)进行一次输出;{
1.一大一小(长度相同)输出上一个;
2.这次放入了同一个(长度不同)长的输出top,为中位数,上一个中位数放入另一个队列
}
个人问题(上榜原因)
1.我心中最好的队列题;
2.用了大部分技巧;
D- Cites and States S
Description
Farmer John 有若干头奶牛。为了训练奶牛们的智力,Farmer John 在谷仓的墙上放了一张美国地图。地图上表明了每个城市及其所在州的代码(前两位大写字母)。
由于奶牛在谷仓里花了很多时间看这张地图,他们开始注意到一些奇怪的关系。例如,FLINT 的前两个字母就是 MIAMI 所在的 FL
州,MIAMI 的前两个字母则是 FLINT 所在的 MI
州。
确切地说,对于两个城市,它们的前两个字母互为对方所在州的名称。
我们称两个城市是一个一对「特殊」的城市,如果他们具有上面的特性,并且来自不同的州。对于总共 N 座城市,奶牛想知道有多少对「特殊」的城市存在。请帮助他们解决这个有趣的地理难题!
Input
输入共 N+1 行。
第一行一个正整数 N,表示地图上的城市的个数。
接下来 N 行,每行两个字符串,分别表示一个城市的名称(2∼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≤N≤2×10^5,城市名称长度不超过 10。
详解
#include<bits/stdc++.h>
using namespace std;
int main()
{
int num,i,sun=0,m=2e5+5;
map<int,int>n[m];
cin>>num;
for(int i=0;i<num;i++){
string a,b;
cin>>a>>b;
int c=(a[0]-'A'+1)*26+(a[1]-'A'+1);
int d=(b[0]-'A'+1)*26+(b[1]-'A'+1);
if(c==d) continue;
n[c][d]++;
sun+=n[d][c];
}
cout<<sun<<endl;
}
思路步骤
1.记录前后两次的字符(数字化)
2.记录这种情况出现次数
3.加上对应情况的次数;
个人问题(上榜原因)
1.运用了关键技巧数字化记录;
2.难想到这种思路;
E-产生冠军
Description
有一群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打一场比赛。
球赛的规则如下:
如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A一定能打败C。
如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。
根据这个规则,无需循环较量,或许就能确定冠军。你的任务就是面对一群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。
Input
输入含有一些选手群,每群选手都以一个整数n(n<1000)开头,后跟n对选手的比赛结果,比赛结果以一对选手名字(中间隔一空格)表示,前者战胜后者。如果n为0,则表示输入结束。
Output
对于每个选手群,若你判断出产生了冠军,则在一行中输出“Yes”,否则在一行中输出“No”。
Sample
Inputcopy | Outputcopy |
---|---|
3 Alice Bob Smith John Alice Smith 5 a c c d d e b e a d 0 | Yes No |
详解
#include<bits/stdc++.h>
using namespace std;
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
long long n,i;
while(1){
cin>>n;
if(n==0) break;
map<string,int> c,l;
for(i=0;i<n;i++){
string a,b;
cin>>a>>b;
c[a]++; c[b]++;
l[b]++;
}
long long lc=(long long)c.size();
long long ll=(long long)l.size();
if(lc-ll==1)
cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
个人问题(上榜原因)
1.当天未作出;
2.思路独特;
F-Make Majority
Description
给定一个序列 [a1,…,an],其中每个元素 ai 要么是 0,要么是 1。你可以对该序列应用多个(可能为零)操作。在每次操作中,你选择两个整数 1≤l≤r≤|a|(其中 |a| 是 a的当前长度),并用单个元素 x替换 [al,…,ar],其中 x 是 [al,…,ar]的大多数。
这里,对于由 00 和 11 组成的序列,其大多数定义如下:假设序列中有 c0 个零和 c1 个一。
- 如果 c0≥c1,则大多数是 0。
- 如果 c0<c1,则大多数是 1。
例如,假设 a=[1,0,0,0,1,1]。如果我们选择 l=1,r=2,则结果序列将是 [0,0,0,1,1]]。如果我们选择 l=4,r=6,则结果序列将是 [1,0,0,1]。
确定是否可以通过有限次操作得到 a=[1]。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 t(1≤t≤41*0^4)。接下来是测试用例的描述。
每个测试用例的第一行包含一个整数 n(1≤n≤⋅10^5)。
每个测试用例的第二行包含一个由 00 和 11 组成的字符串,描述序列 a。
保证所有测试用例中 n 的总和不超过 2⋅1052⋅105。
输出
对于每个测试用例,如果可以得到 a=[1],则打印 YES。否则,打印 NO。你可以以任何形式(大写或小写)输出答案。例如,字符串 yEs、yes、Yes 和 YES 都将被视为肯定回答。
示例
Inputcopy | Outputcopy |
---|---|
5 1 0 1 1 2 01 9 100000001 9 000011000 | No Yes No Yes No |
注意
在示例的第四个测试用例中,初始时 a=[1,0,0,0,0,0,0,0,1]�=[1,0,0,0,0,0,0,0,1]。一组有效的操作序列是:
- 选择 l=2,r=8并应用该操作。 a变为 [1,0,1][1,0,1]。
- 选择 l=1,r=3 并应用该操作。 a 变为 [1][1]。
详解
#include<bits/stdc++.h>
using namespace std;
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int num;
cin>>num;
while(num--){
int n,zero=0,one=0;
bool last=false;
cin>>n;
for(int i=1;i<=n;i++){
char a;
cin>>a;
int num=a-'0';
if(num==0){
last=true;
}
else if(num!=0&&last){
last=false;zero++;one++;
}
else if(num!=0){
one++;
}
}
if(last) zero++;
if(zero>=one) cout<<"No"<<"\n";
else cout<<"Yes"<<"\n";
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/2301_81939891/article/details/140475871