一、pair
1.定义:“二元结构题的替代品”;实际就是含有两个变量的结构体;
相当于:struct pair{
typename1 first;
typename2 second;
}
pair有两个参数,分别对应first和second的数据类型,可以是任意基本数据类型或者容器。
2.定义一个pair的方法为:
pair<typename1,typename2> name;
/* 在pair内会自动排序:先按 typename1从小到大排 :typename1相同;
按typename2从小到大排序*/
3.头文件.#include ,同时,必须要有“using namespace std” ,包含于#include<bits/stdc++.h>中。
二、string
1.C++在STL中加入了string类型,比char str []更方便存储,不必担心内存是否足够、字符串的长度等问题。
2. 定义string的方法为:string name;;
string name [10] 是指有10个名字需要存储;
3.头文件:#include ,同时必须要有“using namespace std”,包含于#include<bits/stdc++.h>中。
4.string的访问:
string str= “ abcd “ ;
for(int i = 0; i < str.length(); i++) printf( “ %c “ ,str[i]);
5.如果要读入或者输出整个字符串,一般只能用cin和cout。如果非要用printf输出string,则需要用c_str()函数将string转换成字符数组。例如:
string str;
cin>>str;
cout<<str<<endl;
printf("%s\n",str.c_str());
三、map
1.定义: map翻译为映射,是STL中的常用容器。(可存储数据)
2.头文件:#include
#include <bits/stdc++.h>
using namespace std;
map<string,int>vis;/*定义变量名*/
int main()
{
ios::sync_with_stdio();
int n,m,page;
string word1,word2;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>word1>>page;/*输入word1的同时相当于将输入了map中*/
vis[word1]=page;/*再将page输入到map中*/
}
cin>>m;
while(m--)
{
cin>>word2;
printf("%d\n",vis[word2]);
}
return 0;
}
problem B:保龄球-map
nefu 1687
#include <bits/stdc++.h>
using namespace std;
map<long long ,int>vis;
int main()
{
int n,m;
long long x;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
vis[x]=i;
}
scanf("%d",&m);
while(m--)
{
scanf("%lld",&x);
printf("%d\n",vis[x]);/*如果map中没有xvis[x]为0*/
}
return 0;
}
problem C:眼红的Medusa
nefu 1686
#include <bits/stdc++.h>
using namespace std;
map<long long ,int>vis;
int main()
{
int n,m;
long long a[100001];
long long x;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
vis[a[i]]=1;/*把第一组数据作为参照,后面还会用到,所以要做一下标记*/
}
for(int i=0;i<m;i++)
{
scanf("%lld",&x);
vis[x]++;
}
for(int i=0;i<n;i++)
if(vis[a[i]]==2)printf("%lld ",a[i]);
return 0;
}
problem E:指数序列
nefu 1677
抓住两点:
1.有数学公式可知 2^v-1= 20+21+22+……2(v-1);
也就是说2^v-1的二进制每一位都为1;
所以找出二进制位为0的个数在补上就可以了;
即找出从0到v-1中间缺的数字;
2.由于2x+2x=2^(x+1),对于一个非降序列,我们可以向上进位得到单调递增序列,如:
1 1 2 3 5——>2 2 3 5——>3 3 5——>4 5
方法一:暴力的方法:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e5+10;
const long long int M=1e18;
ll a[N];
map<ll,int>vis;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
ll ans=a[1];/*a[1]的大小就是第一个元素前面要补的数*/
a[n+1]=M;/*写a[n+1]是为了循环能判断a[n]*/
for(int i=1;i<=n+1;i++)
{
if(a[i]!=a[i-1]&&(i!=1))
{
for(int j=a[i-1];j<a[i];j++)
{
if(!vis[j])/*当vis[j]为0时,一般是a[i-1]++的元素*/
{
if(i!=n+1)ans+=a[i]-j;/*加上中间空余的元素个数*/
break;
}
while(vis[j]>=2)/*所说的点2的进位*/
{
vis[j]-=2;
vis[j+1]++;
}
if(!vis[j])ans++;/*空缺的元素补上,要做一下标记*/
}
}
vis[a[i]]++;/*当i=1时只进行这一步vis[a[1]]++,当出现相等的元素一直++*/
}
cout<<ans<<endl;
return 0;
}
方法二:用map
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
long long num=0,x,cnt;
map<long long,int>vis;
scanf("%lld",&n);
while(n--)
{
scanf("%lld",&x);
vis[x]++; /*标记x出现过*/
if(vis[x]==2)
{
for(long long i=x;vis[i]==2;i++) /*进位*/
{
vis[i]-=2;
vis[i+1]++;
}
}
}
map<long long,int>::iterator it;
for(it=vis.begin();it!=vis.end();it++)
{
if(it->second!=0) /*判断一下是否被减到0*/
{
cnt++; /*计算1的个数*/
if(it->first>num)num=it->first; /*找到最大位数*/
}
}
printf("%lld",num<cnt?0:num-cnt+1);/*若num小于cnt(1的个数)输出num-cnt+1,加一是因为0也要有*/
return 0;
}