本次训练共10题,本文附AC代码和题目链接。
洛谷 P1918 保龄球 (map)
#include <bits/stdc++.h>
using namespace std;
map<int,int>a;//实际上就是定义了一个int a[1e9]的数组,但是普通数组开不到1e9那么大
int main()
{
int n,x1,x2,k;
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x1;
a[x1]=i;
}
cin>>k;
while(k--)
{
cin>>x2;
printf("%d\n",a[x2]);//如果x2之前没出现过,会自动输出0
}
return 0;
}
nefu 1678 查字典 (map)
#include <bits/stdc++.h>
using namespace std;
map<string,int>a;
int main()
{
string word,inquire;//inquire为要查询的单词
int m,n,page;
ios::sync_with_stdio(false);
cin>>n;
while(n--)
{
cin>>word>>page;
a[word]=page;
}
cin>>m;
while(m--)
{
cin>>inquire;
printf("%d\n",a[inquire]);
}
return 0;
}
洛谷 P1271 眼红的Medusa (map)
因为编号最大到2e9,普通数组不能开这么大,所以要用map开一个vis标记数组记录某个编号是否出现。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
map<int,int>vis;
int n,m,cnt,a[N],b[N],ans[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
cin>>b[i],vis[b[i]]=1;
for(int i=1;i<=n;i++)
if(vis[a[i]])ans[++cnt]=a[i];
for(int i=1;i<=cnt;i++)
i==cnt?printf("%d\n",ans[i]):printf("%d ",ans[i]);
return 0;
}
nefu 1676 上网统计 (vector+map)
#include <bits/stdc++.h>
using namespace std;
int n,m,num,tmp;
string id,web;
map<string,int>vis;//记录用户名对应的编号
map<int,string>a;//记录编号对应的用户名
vector<string>ans[1010];//ans[i][j]表示第i个编号的用户第j个访问的网站
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>id>>web;
if(vis[id]==0)//此时输入的id没有出现过
{
vis[id]=++num;//num为用户名对应的编号(从1开始编号)
ans[num].push_back(web);//保存到第num个编号的用户的网站记录
a[num]=id;//保存num编号对应的用户名
}
else//此时输入的id出现过
{
tmp=vis[id];//找到这个id对应的编号
ans[tmp].push_back(web);//保存到第tmp个编号的用户的网站记录
}
}
for(int i=1;i<=num;i++)
{
printf("%s ",a[i].c_str());//输出第i个编号对应的用户名
for(int j=0;j<ans[i].size();j++)//输出第i个编号的用户访问的所有网站
j==ans[i].size()-1?printf("%s\n",ans[i][j].c_str()):printf("%s ",ans[i][j].c_str());
}
return 0;
}
nefu 1679 NOIP 题海战 (map/set)
方法1,map+邻接表/vector
用邻接表存数据,map标记去重题号和选手
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
map<int,int>vis;
map<int,int>flag;
int n,m,x,y,q,num,type,cnt,head[N];
struct edge
{
int to,next;
}e[N];
void add(int x,int y)
{
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
}
int main()
{
ios::sync_with_stdio(false);
memset(head,-1,sizeof(head));
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>num;
flag.clear();
for(int j=1;j<=num;j++)
{
cin>>y;//选手i做过的题号为y
if(flag[y]==1)continue;//同一道题要去重
flag[y]=1;
add(i,y);
}
}
cin>>q;
while(q--)
{
cin>>type>>num;
vis.clear();
flag.clear();
int tot=0;
for(int i=1;i<=num;i++)
{
cin>>x;//选手x
if(flag[x]==1)continue;//同一选手要去重
flag[x]=1;
tot++;//统计去重之后的选手个数
for(int j=head[x];j!=-1;j=e[j].next)
{
y=e[j].to;//被做过的题y
vis[y]++;
}
}
if(type==0)
{
for(int i=1;i<=m;i++)
if(vis[i]==0)printf("%d ",i);
}
else
{
for(int i=1;i<=m;i++)
if(vis[i]==tot)printf("%d ",i);
}
printf("\n");
}
return 0;
}
或者也可以把邻接表存数据改成vector存数据,时间会长一些(78ms)。
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
map<int,int>vis;
map<int,int>flag;
vector<int>s[N];
int n,m,x,y,q,num,type;
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>num;
flag.clear();
for(int j=1;j<=num;j++)
{
cin>>y;//选手i做过的题号为y
if(flag[y]==1)continue;//同一道题要去重
flag[y]=1;
s[i].push_back(y);
}
}
cin>>q;
while(q--)
{
cin>>type>>num;
vis.clear();flag.clear();
int tot=0;
for(int i=1;i<=num;i++)
{
cin>>x;//选手x
if(flag[x]==1)continue;//同一选手要去重
flag[x]=1;
tot++;//统计去重之后的选手个数
for(int j=0;j<s[x].size();j++)
{
y=s[x][j];//被做过的题y
vis[y]++;
}
}
if(type==0)
{
for(int i=1;i<=m;i++)
if(vis[i]==0)printf("%d ",i);
}
else
{
for(int i=1;i<=m;i++)
if(vis[i]==tot)printf("%d ",i);
}
printf("\n");
}
return 0;
}
方法2,map+set
用set存题号直接去重题号,不再去重选手(实际上应该要去重选手,降低时间复杂度),68ms。
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,x,y,q,num,type;
set<int>s[N];
map<int,int>vis;
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>num;
for(int j=1;j<=num;j++)
{
cin>>y;//选手i做过的题号为y(题目必须去重,否则之后不好统计每题被做过的次数)
s[i].insert(y);
}
}
cin>>q;
while(q--)
{
cin>>type>>num;
vis.clear();
for(int i=1;i<=num;i++)
{
cin>>x;//选手x(我在这里没有把选手进行去重,如果同一选手出现多次,程序的运行时间将会延长)
for(set<int>::iterator it=s[x].begin();it!=s[x].end();it++)
vis[*it]++;//选手x做过的题为*it,其次数+1
}
for(int i=1;i<=m;i++)
{
if(type==0&&!vis[i])printf("%d ",i);
else if(type==1&&vis[i]==num)printf("%d ",i);
}
printf("\n");
}
return 0;
}
nefu 1677 指数序列 (set+map)
由于2x + 2x = 2x+1,对于一个非降序列,我们可以向上进位得到单调递增序列,如:
1 1 2 3 5——>2 2 3 5——>3 3 5——>4 5
由于2v-1 = 20 + 21 + 22 +……+ 2v-1,所以我们只需暴力找答案的二进制中0的个数。
#include <bits/stdc++.h>
using namespace std;
int n,x,s,mx;
set<int>ans;
map<int,int>vis;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x;
vis[x]++;
ans.insert(x);
mx=max(mx,x);
}
for(set<int>::iterator it=ans.begin();it!=ans.end();it++)
{
x=*it;
int tmp=vis[x];
vis[x]=tmp%2;
if(vis[x]==0)s++;//统计被删除的数的个数
int k=tmp/2;//将相同的两个数合并,合并后的数大小+1,个数+k
if(!vis[x+1]&&k!=0)
{
ans.insert(x+1);//合并后的数大小+1
mx=max(mx,x+1);//mx记录合并完成后数的最大值
}
vis[x+1]+=k;//合并后的数的个数+k
}
printf("%d\n",mx+1-ans.size()+s);
return 0;
}
nefu 1680 列车调度 (set)
set中数据是有序的,可以直接搭配lower_bound或者upper_bound使用
使用方法:
set<int>s;
set<int>::iterator it=s.upper_bound(x); //返回s中第一个大于x的迭代器
AC代码:
#include <bits/stdc++.h>
using namespace std;
set<int>s;
set<int>::iterator it;
int n,x,ans=1;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x;
if(s.empty())s.insert(x);
else
{
it=s.upper_bound(x);//it是set容器中第一个大于x的迭代器
if(it==s.end())
//x比set容器中的所有数都要大,将x插入,需要增加铁轨
{
s.insert(x);
ans++;
}
else
//x插入到已有的铁轨中合适的位置,删除大于x的第一个数(*it),插入x
{
s.erase(*it);
s.insert(x);
}
}
}
printf("%d\n",ans);
return 0;
}
nefu 1675 中间数 (vector)
因为开数组开不到1e9那么大,所以只能用vector存数据了。
(vector是一个能够存放任意类型的动态数组,能够增加和压缩数据)
#include <bits/stdc++.h>
using namespace std;
vector<int>a;
int main()
{
int i,n,x;
while(cin>>x&&x)
a.push_back(x);//从a[0]开始存储
n=a.size();
if(n&1) printf("%d\n",a[(n-1)/2]);
else printf("%d\n",a[(n-1)/2]+a[n/2]);
return 0;
}
nefu 743 明明的随机数 (set)
#include <bits/stdc++.h>
using namespace std;
set<int>a;
int main()
{
int n,x;
while(cin>>n)
{
a.clear();
while(n--)
{cin>>x;a.insert(x);}
printf("%d\n",a.size());
set<int>::iterator it;
for(it=a.begin();it!=a.end();it++)
it==a.begin()?printf("%d",*it):printf(" %d",*it);
printf("\n");
}
return 0;
}
nefu 1684 第K小整数 (set)
#include <bits/stdc++.h>
using namespace std;
set<int>a;
int main()
{
int n,k,x,cnt,flag;
cin>>n>>k;
while(n--)
{cin>>x;a.insert(x);}
set<int>::iterator it;
flag=cnt=0;
for(it=a.begin();it!=a.end();it++)
{
cnt++;
if(cnt==k){printf("%d\n",*it);flag=1;break;}
}
if(flag==0)printf("NO RESULT\n");
return 0;
}
来源:CSDN
作者:nefu_ljw
链接:https://blog.csdn.net/ljw_study_in_CSDN/article/details/86478604