做错的题和比较坑的题合集

1、林大oj-1662-Blash数集-队列-set

错误做法:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    long long a,n;
    double j;
    set<long long>vis1,vis2,vis3;
    set<long long>::iterator it;
    scanf("%lld %lld",&a,&n);
    vis1.insert(a);
    vis3.insert(a);
    j=1;
    while(1)
    {
        vis2.clear();
        for(it=vis1.begin();it!=vis1.end();it++)
        {
            vis2.insert(2*(*it)+1);
            vis2.insert(3*(*it)+1);
        }
        vis1.clear();
        for(it=vis2.begin();it!=vis2.end();it++)
        {
            vis1.insert(*it);
            vis3.insert(*it);
        }
        if((1+2*(pow(2,j)-1))/j>n)
            break;
        j++;
    }
    it=vis3.begin();
    for(int i=1;i<n;i++)
    {
        it++;
    }
    printf("%lld",(*it));
    return 0;
}

由于循环里套循环,而且循环过多导致tle,而且循环结束条件不应使用set.size()来判断。
如果发现自己算法复杂度过高应及时转变思维,判断、循环中止条件应最简。
正确做法

#include <bits/stdc++.h>

using namespace std;

int main()
{
    long long a,n;
    double j;
    set<long long>vis1;
    set<long long>::iterator it;
    scanf("%lld %lld",&a,&n);
    j=1;
    vis1.insert(a);
    for(it=vis1.begin();it!=vis1.end();it++)
    {
        vis1.insert(2*(*it)+1);
        vis1.insert(3*(*it)+1);
        if(j>=n)
            break;
        j++;
    }
    it=vis1.begin();
    for(int i=1;i<n;i++)
    {
        it++;
    }
    printf("%lld",(*it));
    return 0;
}

最大减少循环复杂度,并且使用最为简便的循环终止条件;

2、林大oj-1676-上网统计-vector/map

注意点:(1)对于有一对多个变量时,可以用编号来确定各个变量组。
(2)当用cin加速时,林大oj上不能用cout<<endl,不然会报错。

#include <bits/stdc++.h>

using namespace std;

map<string,int>a;//用来名字去重
map<int,string>b;//用来名字排序
vector<string>vis[1010];//用来记录名字所对应的网站
//都是用编号来对应数据
int n,m,cnt,t;
string name,web;
int main()
{
    a.clear();
    ios::sync_with_stdio(false);
    cin>>n>>m;
    while(m--)
    {
        cin>>name>>web;
        if(a[name]==0)//如果name没有录入过
        {
            a[name]=++cnt;
            vis[cnt].push_back(web);
            b[cnt]=name;
        }else//如果name录入过
        {
            t=a[name];
            vis[t].push_back(web);
        }
    }
    for(int i=1;i<=cnt;i++)
    {
        printf("%s",b[i].c_str());
        for(int j=0;j<vis[i].size();j++)
        {
            printf(" %s",vis[i][j].c_str());
        }
        printf("\n");//一定不要用cout<<endl;
    }
    return 0;
}

综合来说就是建立一种可以解决问题的一一对应关系。

3、林大oj-2124-钻石收集者-vector

运用了桶排序的思想,将复杂的计数计算转化为逐步算减法。

#include <bits/stdc++.h>

using namespace std;

const int N=1e5;
int n,k,x,ans,cnt[N+10],sum[N+10];

int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        cnt[x]++;//桶排序计数
    }
    for(int i=0;i<=N;i++)
    {
        if(i==0) sum[i]=cnt[i];//对于i=0的时候特殊判断
        else sum[i]=sum[i-1]+cnt[i];//不断递加,形成一个数和的增序列
    }
    for(int i=0;i+k<=N;i++)
    {
        if(i==0) ans=sum[i+k];//特判
        else ans=max(ans,sum[i+k]-sum[i-1]);//减法求区间大小,求[i,i+k]区间的最大值
    }
    printf("%d",ans);
    return 0;
}

例子模拟
k=3
—— 0 1 2 3 4 5 6 7 8 9 10
cnt—0 2 0 1 1 0 1 0 0 0 0
—— 0 1 2 3 4 5 6 7
sum 0 2 2 3 4 4 5 5

4、林大oj-2127-圆桌问题-vector

另一种思路,不用erase()而是将a[pos]=0,但这种方法会让数数时特别麻烦,导致超时。

#include <bits/stdc++.h>

using namespace std;

vector<int>a;
int n,m;

int main()
{
    while(cin>>n>>m){
        a.clear();
        for(int i=0;i<2*n;i++)//从0开始放人
            a.push_back(i);
        int pos=0;
        for(int i=0;i<n;i++){//淘汰n个人
            pos=(pos+m-1)%a.size();//被淘汰的人在vector中的下标(vector的长度在变化)
            a.erase(a.begin()+pos);
        }
        int p=0;
        for(int i=0;i<2*n;i++){
            if(i==a[p]&&p<n){/*现在未被淘汰的人在vector中的值与其序号相等,被淘汰的人值为0;
                               如果a[p]不存在则此值得零,这种方法是可以的,但不能用来赋值*/
                p++;
                printf("G");
            }
            else printf("B");
        }
        printf("\n");
    }
    return 0;
}

5、大一寒假牛客网比赛-成绩查询ing

注意点:此题与“林大oj-1676-上网统计-vector/map”题类似,注意所选保存信息特殊量的唯一性,本题中不能选用成绩作为特殊量来保存信息,因为成绩有可能重复出现。

#include <bits/stdc++.h>

using namespace std;

long long n,m,gra,sex,id,flag;
string na;

map<string,long long>a;
map<long long,set<string>>b;
set<string>::iterator it;
map<string,long long>c;
map<string,long long>d;

int main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        cin>>na>>gra>>sex;
        scanf("%lld",&id);
        a[na]=gra;
        b[gra].insert(na);
        c[na]=sex;
        d[na]=id;
    }
    scanf("%lld",&m);
    while(m--)
    {
        cin>>flag;
        if(flag==1)
        {
            cin>>na;
            printf("%lld %lld %lld\n",a[na],d[na],c[na]);
        }else if(flag==2)
        {
            cin>>gra;
            for(it=b[gra].begin();it!=b[gra].end();it++)
            {
                printf("%s\n",(*it).c_str());
            }
        }
    }
    return 0;
}

6、大一寒假牛客网比赛-上进的凡凡

分治思想

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100005
int a[N];
ll f(ll x)
{
    ll ans=((x+1)*x)/2;//计算子数组(字串)的公式
    return ans;
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    ll t=0;
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>a[i+1]||i==n)//即从每个 a[i]>a[i+1]的地方断开
            {
                ans+=f(i-t);//计算从a[i]到上一个断点之间的子数组(子串)
                t=i;//记录此断点
            }
    }
    cout<<ans;
    return 0;
}

7、林大oj-1677-指数序列

所用到的数学公式:

  1. 2n-1=20+21+22+……2n
  2. 2n+2n=2n+1
#include <bits/stdc++.h>
using namespace std;
/*
  2^n+2^n=2^(n+1)
*/
set<int> s;
int main()
{
    int n;
    scanf("%d", &n);
    int cnt = 0;
    
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &tmp);
        while (s.count(tmp))//做等效的加法来过滤相同元素
        {
            s.erase(tmp);
            tmp++;
        }
        s.insert(tmp);
    }
    int las = -1;//由于0位起始所以las的初始值要设为0-1
    int tmp = 0;
    for (set<int>::iterator iter = s.begin(); iter != s.end(); iter++)//预处理完成,开始遍历操作
    {
        cnt += (*iter - las - 1);//看前后两个数差值是否为1,不是则在差值的基础上减一计数
        las = *iter;
    }
    printf("%d",cnt);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值