大一寒假训练九(vector , map, set)【更新完成】

有些话、适合烂在心里 提交于 2020-02-17 02:08:54

本次训练共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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!