做错的题和比较坑的题合集
- 1、[林大oj-1662-Blash数集-队列-set](http://acm.nefu.edu.cn/problemShow.php?problem_id=1662)
- 2、[林大oj-1676-上网统计-vector/map](http://acm.nefu.edu.cn/problemShow.php?problem_id=1676)
- 3、[林大oj-2124-钻石收集者-vector](http://acm.nefu.edu.cn/problemShow.php?problem_id=2124)
- 4、[林大oj-2127-圆桌问题-vector](http://acm.nefu.edu.cn/problemShow.php?problem_id=2127)
- 5、大一寒假牛客网比赛-成绩查询ing
- 6、[大一寒假牛客网比赛-上进的凡凡](https://ac.nowcoder.com/acm/contest/11746/C)
- 7、[林大oj-1677-指数序列](http://acm.nefu.edu.cn/problemShow.php?problem_id=1677)
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-指数序列
所用到的数学公式:
- 2n-1=20+21+22+……2n
- 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;
}