目录
A - Bombing
题目:(改编版翻译,中心题意不变)
你现在沉迷于瘟疫公司这款游戏,现在游戏推出了新模式,你迫不及待地打开了游戏。
现在,在一个1e9×1e9的平面图上有n座城市(n<=100000),系统已经为你提供了它们的坐标。
你有m架轰炸机,每架轰炸机上都携带着病毒炸弹。而每一架轰炸机的飞行模式为c d。
- 当c=0时,轰炸机将会朝着x=d的方向轰炸城市;
- 当c=1时,轰炸机将会朝着y=d的方向轰炸城市。
现在你想知道你的每一架轰炸机摧毁了多少城市。
(当城市A被摧毁时,城市A不能再被记入后面的轰炸机战绩之中)
思路:
设计map容器存储数据:
map<int,multiset<int> > mx,my;
mx[x坐标]=>{y1,y2,y3...} 落在x坐标上的y坐标集合
my[y坐标]=>{x1,x2,x3...} 落在y坐标上的x坐标集合
学过数据库系统的同学就会对这题的中心更加理解:删除一条属性时首先去除它的参照完整性。
具体看代码。
-
考察点:可重复元素集合(multiset),映射对(Map),STL,思维
-
坑点:已被摧毁的城市不能再被计入战绩之中
代码:
#include<iostream>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
int main(){
int n,m;
ios::sync_with_stdio(false);
while(cin>>n>>m&&(n+m)!=0){
map<int,multiset<int> > mx,my;
multiset<int>::iterator it;
int x,y,c,d;
for(int i=0;i<n;i++){
cin>>x>>y;
mx[x].insert(y);
my[y].insert(x);
}
for(int i=0;i<m;i++){
cin>>c>>d;
int bomb=0;
if(!c){
bomb=mx[d].size();
for(it=mx[d].begin();it!=mx[d].end();it++){
my[*it].erase(d);
}
mx[d].clear();
}
else{
bomb=my[d].size();
for(it=my[d].begin();it!=my[d].end();it++){
mx[*it].erase(d);
}
my[d].clear();
}
cout<<bomb<<endl;
}
cout<<endl;
}
}
B - Constructing the Array
题意:
给定一个长为n的空数组,将1~n的数字放到数组之中。
放置规则:
- 选择长度最长的空白元素区间,如果有多个,选择最靠左的区间;
- 将 i 放置在 (l+r)/2 的位置;
输出最后的数组。
思路:
第一种:拿数字找位置(二分+优先队列)
将空元素区间存储在优先队列之中并设计排序:
struct node
{
int l,r;
node() {}
node(int ll,int rr):l(ll),r(rr) {}
};
struct cmp
{
bool operator()(node a,node b)
{
if(a.r-a.l!=b.r-b.l)
return (a.r-a.l)<(b.r-b.l);
else
return a.l>b.l;
}
};
priority_queue<node,vector<node>,cmp > q;
二分处理问题,模拟全过程即可。
-
考察点:优先队列(Priority queue),二分,数据结构,模拟,思维
代码:
#include<iostream>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
int ans[maxn];
struct node
{
int l,r;
node() {}
node(int ll,int rr):l(ll),r(rr) {}
};
struct cmp
{
bool operator()(node a,node b)
{
if(a.r-a.l!=b.r-b.l)
return (a.r-a.l)<(b.r-b.l);
else
return a.l>b.l;
}
};
priority_queue<node,vector<node>,cmp > q;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
q.push(node(1,n));
int cnt=1;
while(!q.empty())
{
node tmp=q.top();
q.pop();
int mid=(tmp.l+tmp.r)/2;
ans[mid]=cnt++;
if(mid-1>=tmp.l)
q.push(node(tmp.l,mid-1));
if(mid+1<=tmp.r)
q.push(node(mid+1,tmp.r));
}
for(int i=1; i<=n; i++)
{
if(i!=1)
cout<<" ";
cout<<ans[i];
}
cout<<endl;
}
}
C - 士兵队列训练问题
题意:
中文题唉大哥,都是中国人你问我?
思路:
模拟题,数组、vector都可以。
需要注意的是,如果用的是vector中的erase函数,需要找出每次迭代器需要移动的次数:
- 当报2时,移动次数为1;
- 当报3时,移动次数为2;
-
考察点:思维,模拟
代码:
#include<bits/stdc++.h>
#define inf 0x3f3f3f
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
int a[maxn];
bool b[maxn];
int main()
{
int n,cnt=0;
vector<int>q;
while(cin>>n)
{
for(int i=0; i<n; i++)
cin>>a[i];
for(int o=0; o<n; o++)
{
q.clear();
for(int i=1; i<=a[o]; i++)
q.push_back(i);
vector<int>::iterator it;
while(q.size()>3)
{
cnt=0;
while(1)
{
cnt=cnt+1;
if(cnt>=q.size())
break;
q.erase(q.begin()+cnt);
}
// for(it=q.begin(); it!=q.end(); it++)
// {
// cout<<*it<<' ';
// }
// cout<<endl;
if(q.size()<=3)
break;
cnt=0;
while(1)
{
cnt=cnt+2;
if(cnt>=q.size())
break;
q.erase(q.begin()+cnt);
}
// for(it=q.begin(); it!=q.end(); it++)
// {
// cout<<*it<<' ';
// }
// cout<<endl;
// cout<<"-----------------------------------------------"<<endl;
}
cnt=0;
for(it=q.begin(); it!=q.end(); it++)
{
if(cnt)
cout<<' ';
cnt++;
cout<<*it;
}
cout<<endl;
}
}
}
D - Anagram
题意:
给出仅含有大写字母与小写字母组成的字符串s,按照题目中给出的字典序大小顺序由小到大输出s的所有排列结果。
思路:
使用stl提供的next_permutation()即可解决问题。
-
考察点:全排列,字典序,STL
-
坑点:题目中有给定的字典序
代码:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
bool cmp(char a,char b){
if(a<='z'&&a>='a'){
if(b<='z'&&b>='a') return a<b;
else return a<(b+32);
}
else{
if(b<='z'&&b>='a') return (a+32)<=b;
else return a<b;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
char s[20];
scanf("%s",s);
int len=strlen(s);
sort(s,s+len,cmp);
do{
printf("%s\n",s);
}while(next_permutation(s,s+len,cmp));
}
return 0;
}
E - Fence Repair
题意:(改编版翻译,题意不变)
这里有n个木板,你请了一个木匠把它们接在一起去。
当木匠将一块长为a的木板与一块长为b的木板接成一块长为(a+b)的木板时,他会收取(a+b)元钱。
你也不是什么大户人家,请求出你需要把所有木板接在一起所要支付的最小价格。
思路:
每次都将当前最短的两个木板接起来就可以了。(哈夫曼树)
-
考察点:优先队列(Priority queue),哈夫曼树,贪心
-
坑点:数据有点大,开longlong
代码:
#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
int main(){
int n,x;
cin>>n;
priority_queue<int,vector<int>,greater<int> > p;
for(int i=0;i<n;i++){
cin>>x;
p.push(x);
}
ll ans=0;
while(p.size()>=2){
ll a=p.top();
p.pop();
ll b=p.top();
p.pop();
ans+=(a+b);
p.push(a+b);
}
cout<<ans<<endl;
}
F - Black Box
题意:
给定一个长为n的序列a,并有m次询问。
第i次询问的内容为:由序列a的前xi个数字组成的新序列里第i大的数字为多少?
保证每次的询问合理并且 x[i-1]<=x[i]。
思路:
与Day2的C题有着异曲同工之妙,对顶堆问题。
设计两个优先队列:
priority_queue<int> big; //大根堆,存储前i-1个数
priority_queue<int,vector<int>,greater<int> > small; //小根堆,存储第i~第xi个数
模拟整个过程,期间维护:当我们需要求第i大的数时,big.size()==i-1。
-
考察点:优先队列(Priority queue),对顶堆,数据结构,STL
代码:
#include<iostream>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
int a[30500];
int main()
{
int n,m,x;
while(cin>>n>>m)
{
priority_queue<int> big;
priority_queue<int,vector<int>,greater<int> > small;
for(int i=0; i<n; i++)
cin>>a[i];
int pos=0;
for(int i=1; i<=m; i++)
{
cin>>x;
while(pos<x)
{
small.push(a[pos++]);
if(!big.empty()&&big.top()>small.top())
{
int x=big.top();
big.pop();
small.push(x);
int y=small.top();
small.pop();
big.push(y);
}
}
int ans=small.top();
cout<<ans<<endl;
small.pop();
big.push(ans);
}
}
}
G - 迷宫问题
-
考察点:队列(Queue),栈(Stack),BFS,递归