12-STL+位运算+离散化+中位数+链表

1set,去重

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;
}

2multiset

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;
}

3pair

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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值