1、set,去重
AcWing 1610. 朋友数
如果两个整数各位数字的和是一样的,则被称为是“朋友数”,而那个公共的和就是它们的“朋友证号”。
例如 123和 51 就是朋友数,因为 1+2+3=5+1=6,而 6就是它们的朋友证号。
给定一些整数,要求你统计一下它们中有多少个不同的朋友证号。
【输入格式】
输入第一行给出正整数 N。
随后一行给出 N个正整数,数字间以空格分隔。
【输出格式】
首先第一行输出给定数字中不同的朋友证号的个数;
随后一行按递增顺序输出这些朋友证号,数字间隔一个空格,且行末不得有多余空格。
数据范围
1≤N≤10000
给定正整数均不超过 10000。
输入样例:
8
123 899 51 998 27 33 36 12
输出样例:
4
3 6 9 26
<代码1>桶
#include<bits/stdc++.h>
using namespace std;
const int N=100;
int tong[N],n,ans;
void fen(int x)
{
int res=0;
while(x)
{
res+=x%10;
x/=10;
}
if(tong[res]==0)ans++;
tong[res]++;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
fen(x);
}
cout<<ans<<endl;
for(int i=0;i<=50;i++)
if(tong[i])cout<<i<<' ';
return 0;
}
<代码2>unique
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n;
int s[N];
int fen(int x)
{
int res=0;
while(x)
{
res+=x%10;
x/=10;
}
return res;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
s[i]=fen(x);
}
sort(s+1,s+n+1);
n=unique(s+1,s+n+1)-s-1;//stl去重
/*
int m=0;//手写去重
for(int i=1;i<=n;i++)
if(s[i]!=s[i-1])
s[++m]=s[i];
n=m;
*/
cout<<n<<endl;
for(int i=1;i<=n;i++)
cout<<s[i]<<' ';
return 0;
}
<代码3>set
#include<bits/stdc++.h>
using namespace std;
const int N=100;
int n;
set<int>s;
int fen(int x)
{
int res=0;
while(x)
{
res+=x%10;
x/=10;
}
return res;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
s.insert(fen(x));
}
cout<<s.size()<<endl;
for(set<int>::iterator it=s.begin();it!=s.end();it++)
cout<<*it<<' ';
return 0;
}
2、multiset
1372:小明的账单
【题目描述】
小明在一次聚会中,不慎遗失了自己的钱包,在接下来的日子,面对小明的将是一系列的补卡手续和堆积的账单… 在小明的百般恳求下,老板最终同意延缓账单的支付时间。可老板又提出,必须从目前还没有支付的所有账单中选出面额最大和最小的两张,并把他们付清。还没有支付的账单会被保留到下一天。 请你帮他计算出支付的顺序。
【输入】
第1行:一个正整数N(N≤15,000),表示小明补办银联卡总共的天数。
第2行到第N+1 行:每一行描述一天中收到的帐单。先是一个非负整数M≤100,表示当天收到的账单数,后跟M个正整数(都小于1,000,000,000),表示每张帐单的面额。
输入数据保证每天都可以支付两张帐单。
【输出】
输出共N 行,每行两个用空格分隔的整数,分别表示当天支付的面额最小和最大的支票的面额。
【输入样例】
4
3 3 6 5
2 8 2
3 7 1 7
0
【输出样例】
3 6
2 8
1 7
5 7
<代码>
#include<bits/stdc++.h>
using namespace std;
int n,m,x;
multiset<int>s;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
s.insert(x);
}
multiset<int>::iterator it;
it=s.begin();
printf("%d ",*it);
s.erase(it);
it=--s.end();
printf("%d\n",*it);
s.erase(it);
}
return 0;
}
3、pair
1147:最高分数的学生姓名
【题目描述】
输入学生的人数,然后再输入每位学生的分数和姓名,求获得最高分数的学生的姓名。
【输入】
第一行输入一个正整数N(N <= 100),表示学生人数。接着输入N行,每行格式如下:
分数 姓名
分数是一个非负整数,且小于等于100;
姓名为一个连续的字符串,中间没有空格,长度不超过20。
数据保证最高分只有一位同学。
【输出】
获得最高分数同学的姓名。
【输入样例】
5
87 lilei
99 hanmeimei
97 lily
96 lucy
77 jim
【输出样例】
hanmeimei
<代码>
#include<bits/stdc++.h>
using namespace std;
int main()
{
pair<int,string> p[101];
int n,t=0;cin>>n;
for(int i=1;i<=n;i++)
{
int c;string s;
cin>>c>>s;
p[++t]=make_pair(-c,s);
}
sort(p+1,p+t+1);
cout<<p[1].second<<endl;
return 0;
}
4、位运算
AcWing 801. 二进制中1的个数
给定一个长度为 n 的数列,请你求出数列中每个数的二进制表示中 1的个数。
【输入格式】
第一行包含整数 n。
第二行包含 n个整数,表示整个数列。
【输出格式】
共一行,包含 n个整数,其中的第 i 个数表示数列中的第 i 个数的二进制表示中 1的个数。
数据范围
1≤n≤100000,
0≤数列中元素的值≤10^9
输入样例:
5
1 2 3 4 5
输出样例:
1 1 2 1 2
<代码>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+1;
int n,a;
int main()
{
cin>>n;
while(n--)
{
scanf("%d",&a);
int res=0;
while(a)
{
if(a&1)res++;//a%=2
a>>=1;//a/=2
}
cout<<res<<' ';
}
return 0;
}
5、离散化
AcWing 802. 区间和
假定有一个无限长的数轴,数轴上每个坐标上的数都是 0。
现在,我们首先进行 n次操作,每次操作将某一位置 x 上的数加 c。
接下来,进行 m次询问,每个询问包含两个整数 l 和 r,你需要求出在区间 [l,r]之间的所有数的和。
【输入格式】
第一行包含两个整数 n和 m。
接下来 n行,每行包含两个整数 x 和 c。
再接下来 m行,每行包含两个整数 l 和 r。
【输出格式】
共 m行,每行输出一个询问中所求的区间内数字和。
数据范围
−10^9≤x≤10^9,
1≤n,m≤10^5,
−10^9≤l≤r≤10^9,
−10000≤c≤10000
输入样例:
3 3
1 2
3 6
7 5
1 3
4 6
7 8
输出样例:
8
0
5
<代码>
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int a[N],b[N],num[N],n,m,l,r;
long long sum[N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i],&b[i]);
num[i]=a[i];
}
sort(num+1,num+n+1);
int cnt=unique(num+1,num+n+1)-(num+1);//去重
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(num+1,num+cnt+1,a[i])-num;//查找位置
sum[a[i]]+=b[i];
}
for(int i=1;i<=cnt+1;i++)
sum[i]+=sum[i-1];//前缀和
while(m--)
{
scanf("%d%d",&l,&r);
int s=lower_bound(num+1,num+cnt+1,l)-num;
int t=lower_bound(num+1,num+cnt+1,r)-num;
if(num[t]>r)t--;
if(t>=s)printf("%d\n",sum[t]-sum[s-1]);
else printf("0\n");
}
return 0;
}
6、中位数
AcWing 104. 货仓选址
在一条数轴上有 N 家商店,它们的坐标分别为 A1∼AN。
现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。
为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。
【输入格式】
第一行输入整数 N。
第二行 N个整数 A1∼AN。
【输出格式】
输出一个整数,表示距离之和的最小值。
数据范围
1≤N≤100000,
0≤Ai≤40000
输入样例:
4
6 2 9 1
输出样例:
12
<代码>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+1;
int n,a[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
ll ans=0;
for(int i=1;i<=n;i++)
ans+=abs(a[i]-a[(n+1)/2]);
cout<<ans<<endl;
return 0;
}
7、单链表
AcWing 826. 单链表
实现一个单链表,链表初始为空,支持三种操作:
1、向链表头插入一个数;
2、删除第 k 个插入的数后面的数;
3、在第 k个插入的数后插入一个数。
现在要对该链表进行 M次操作,进行完所有操作后,从头到尾输出整个链表。
注意:题目中第 k个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n个插入的数。
【输入格式】
第一行包含整数 M,表示操作次数。
接下来 M行,每行包含一个操作命令,操作命令可能为以下几种:
H x,表示向链表头插入一个数 x 。
D k,表示删除第 k 个插入的数后面的数(当 k 为 0时,表示删除头结点)。
I k x,表示在第 k 个插入的数后面插入一个数 x(此操作中 k 均大于 0)。
【输出格式】
共一行,将整个链表从头到尾输出。
数据范围
1≤M≤100000
所有操作保证合法。
输入样例:
10
H 9
I 1 1
D 1
D 0
H 6
I 3 6
I 4 5
I 4 5
I 3 4
D 6
输出样例:
6 4 6 5
<代码>
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+4;
int a[N],nxt[N],m,n;
void ins(int k,int x)
{
a[++n]=x;
nxt[n]=nxt[k];
nxt[k]=n;
}
void del(int k)
{
nxt[k]=nxt[nxt[k]];
}
int main()
{
cin>>m;
while(m--)
{
char c[2];
int k,x;
scanf("%s%d",&c,&k);
if(c[0]=='H')ins(0,k);
if(c[0]=='D')del(k);
if(c[0]=='I'){
scanf("%d",&x);
ins(k,x);
}
}
for(int i=nxt[0];i;i=nxt[i])
printf("%d ",a[i]);
return 0;
}
8、双链表
AcWing 827. 双链表
实现一个双链表,双链表初始为空,支持 5种操作:
在最左侧插入一个数;
在最右侧插入一个数;
将第 k 个插入的数删除;
在第 k 个插入的数左侧插入一个数;
在第 k 个插入的数右侧插入一个数
现在要对该链表进行 M次操作,进行完所有操作后,从左到右输出整个链表。
注意:题目中第 k个插入的数并不是指当前链表的第 k 个数。例如操作过程中一共插入了 n 个数,则按照插入的时间顺序,这 n 个数依次为:第 1 个插入的数,第 2 个插入的数,…第 n个插入的数。
【输入格式】
第一行包含整数 M,表示操作次数。
接下来 M行,每行包含一个操作命令,操作命令可能为以下几种:
L x,表示在链表的最左端插入数 x 。
R x
,表示在链表的最右端插入数 x 。
D k
,表示将第 k 个插入的数删除。
IL k x
,表示在第 k 个插入的数左侧插入一个数。
IR k x
,表示在第 k个插入的数右侧插入一个数。
【输出格式】
共一行,将整个链表从左到右输出。
数据范围
1≤M≤100000
所有操作保证合法。
输入样例:
10
R 7
D 1
L 3
IL 2 10
D 3
IL 2 7
L 8
R 9
IL 4 7
IR 2 2
输出样例:
8 7 7 3 2 9
<代码>
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int pre[N],nxt[N],a[N],n,m;
void ins(int k,int x)
{
a[++n]=x;
nxt[n]=nxt[k];pre[nxt[k]]=n;
nxt[k]=n;pre[n]=k;
}
void del(int k)
{
nxt[k]=nxt[nxt[k]];
pre[nxt[k]]=k;
}
int main()
{
cin>>m;
nxt[0]=m+1,pre[m+1]=0;
for(int i=1;i<=m;i++)
{
char s[3];
int k,x;
scanf("%s%d",&s,&k);
if(s[0]=='L')ins(0,k);
if(s[0]=='R')ins(pre[m+1],k);
if(s[0]=='D')del(pre[k]);
if(s[0]=='I')
{
scanf("%d",&x);
if(s[1]=='L')ins(pre[k],x);
else ins(k,x);
}
}
for(int i=nxt[0];i!=m+1;i=nxt[i])
{
printf("%d ",a[i]);
}
return 0;
}