#include
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;
}
#include
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;
}
因为编号最大到2e9,普通数组不能开这么大,所以要用map开一个vis标记数组记录某个编号是否出现。
#include
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;
}
由于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
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;
}
———————————————————————————————————————————————
#include
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;
}
#include
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;
}
#include
using namespace std;
int t,opt;
string name;
set<string>s;
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>opt>>name;
if(opt==0)s.insert(name);
else
{
if(s.find(name)!=s.end())printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
set中数据是有序的,可以直接搭配lower_bound或者upper_bound使用
使用方法:
set<int>s;
set<int>::iterator it=s.upper_bound(x); //返回s中第一个大于x的迭代器
AC代码:
#include
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;
}
#include
using namespace std;
set<int>s[52];
int n,m,k,x,num1,num2;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>m;
while(m--)
{
cin>>x;
s[i].insert(x);
}
}
cin>>k;
while(k--)
{
cin>>num1>>num2;
int a=0;//两数集重复的个数为a
for(set<int>::iterator it=s[num1].begin();it!=s[num1].end();it++)
if(s[num2].count(*it))a++;
int b=s[num1].size()+s[num2].size()-a;//两数集不重复的个数为b
printf("%.2lf%%\n",1.0*a/(1.0*b)*100.0);
}
return 0;
}
用set模拟,对于每个答案维护一个set集合。
#include
using namespace std;
const int N=1e3+10;
int n,m,x,k,num,type;
set<int>s[N],quanji,ans;
set<int>::iterator it;
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>>x;//选手i做过的题号为x(题目必须去重)
s[i].insert(x);
}
}
for(int i=1;i<=m;i++)
quanji.insert(i);//预处理全集
cin>>k;
while(k--)
{
cin>>type>>num;
ans=quanji;//两个set之间可以用等于号赋值
if(type==0)//比赛,他要保证所出的题都没有被任何一个参赛学生做过
{
for(int i=1;i<=num;i++)
{
cin>>x;//选手编号为x
for(it=ans.begin();it!=ans.end();)
{
if(s[x].count(*it))ans.erase(it++);//筛掉选手x做过的所有题
else it++;
}
}
}
else//训练,他要保证所出的题都被每一个参赛学生做过
{
for(int i=1;i<=num;i++)
{
cin>>x;//选手编号为x
for(it=ans.begin();it!=ans.end();)
{
if(!s[x].count(*it))ans.erase(it++);//筛掉选手x没做过的所有题
else it++;
}
}
}
for(it=ans.begin();it!=ans.end();it++)
printf("%d ",*it);
printf("\n");
}
return 0;
}
———————————————————————————————————————————————
vector是一个能够存放任意类型的动态数组,比较方便增加和压缩数据。
#include
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;
}
#include
using namespace std;
const int N=1e4+10;
int n,m,x,y;
vector<int>a[N];
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m)
cin>>n>>m;
{
while(m--)
{
cin>>x>>y;
a[x].push_back(y);
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<a[i].size();j++)
j==a[i].size()-1?printf("%d",a[i][j]):printf("%d ",a[i][j]);
printf("\n");
a[i].clear();
}
}
return 0;
}
#pragma GCC optimize(2)
#include
using namespace std;
const int N=1e5+10;
int n,m,x,y;
vector<int>a[N];
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m)
{
for(int i=1;i<=n;i++)
{
a[i].clear();
a[i].push_back(i);
}
while(m--)
{
cin>>x>>y;
if(x==y||a[y].empty())continue;
for(int i=0;i<a[y].size();i++)//比迭代器访问快一点,也比insert整体插入要快
a[x].push_back(a[y][i]);
a[y].clear();
}
for(int i=1;i<=n;i++)
{
if(a[i].size()==0)printf("-1\n");
else
{
for(int j=0;j<a[i].size();j++)
j==a[i].size()-1?printf("%d\n",a[i][j]):printf("%d ",a[i][j]);
}
}
}
return 0;
}
vector模拟淘汰的过程,标记被淘汰的人的编号。
#pragma GCC optimize(2)
#include
using namespace std;
const int N=2e4+10;
int n,m,vis[N];
vector<int>ans;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m)
{
ans.clear();
memset(vis,0,sizeof(vis));
for(int i=0;i<2*n;i++)//从0开始放,方便之后的取余处理,人从0开始编号
ans.push_back(i);
int pos=0;
for(int i=0;i<n;i++)//淘汰n个人
{
pos=(pos+m-1)%ans.size();//pos是被淘汰的人在vector中的下标(vector长度在变化)
vis[ans[pos]]=1;//标记被淘汰的人的编号
ans.erase(ans.begin()+pos);//淘汰
}
for(int i=0;i<2*n;i++)
{
if(vis[i])printf("B");
else printf("G");
}
printf("\n");
}
return 0;
}
#include
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;
}
这题和vector没什么关系,能用数组的就用数组写;需要动态变化比较多的,方便模拟的就用vector。
桶排序的思想,记录x出现的次数,存放到cnt[x]里,然后求cnt数组的前缀和,遍历一次前缀和数组取[i,i+k]区间的最大值,即答案为: m a x ( s u m [ i + k ] − s u m [ i − 1 ] ) , i ∈ [ 0 , N − k ] max(sum[i+k]-sum[i-1]),i∈[0,N-k] max(sum[i+k]−sum[i−1]),i∈[0,N−k]
这题用尺取法也可以,代码就不写了。以下给出前缀和方法的代码:
#include
using namespace std;
const int N=1e5;
int n,k,x,mx,cnt[N+10],sum[N+10];
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>x;
cnt[x]++;//记录x出现的次数
}
sum[-1]=0;//这句话是有效的,但有风险
for(int i=0;i<=N+k;i++)
sum[i]=sum[i-1]+cnt[i];
for(int i=0;i<=N+k;i++)
mx=max(mx,sum[i+k]-sum[i-1]);
printf("%d\n",mx);
return 0;
}
[L,R]区间的和是sum[R]-sum[L-1],如果L=0,显然会越界,但是又必须从L=0开始取,所以只能写sum[-1]=0;
。以上的代码虽然能AC,但是存在隐患,sum[-1]=0;
下标越界(在一般情况下,对数组越界访问都是坚决禁止的。但是在某些特定场合,也会有a[-1]这样的访问方式,这和编译器的具体实现有关。)
那就特判i=0的情况,这样写比较保险:
#include
using namespace std;
const int N=1e5;
int n,k,x,mx,cnt[N+10],sum[N+10];
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>x;
cnt[x]++;//记录x出现的次数
}
for(int i=0;i<=N+k;i++)
{
if(i==0)sum[i]=cnt[i];//如果写成sum[i]=sum[i-1]+cnt[i]; i-1会越界
else sum[i]=sum[i-1]+cnt[i];
}
for(int i=0;i<=N+k;i++)
{
if(i==0)mx=sum[i+k];
else mx=max(mx,sum[i+k]-sum[i-1]);
}
printf("%d\n",mx);
return 0;
}