A-B数对

题目描述

题目看多了也有审美疲劳,于是我舍弃了大家所熟悉的A+B Problem,改用A-B了哈哈!

好吧,题目是这样的:给出一串数以及一个数字C,要求计算出所有A-B=C的数对的个数。(不同位置的数字一样的数对算不同的数对)

输入格式

第一行包括2个非负整数N和C,中间用空格隔开。 第二行有N个整数,中间用空格隔开,作为要求处理的那串数。

输出格式

输出一行,表示该串数中包含的所有满足A-B=C的数对的个数。

样例

input

4 1
1 1 2 3

output

3

思路:

这道题用到了一个二分查找的方法,需要查找a。但是这里麻烦的是有重复的数字,所以这里要用到一个去重的操作,例如1 1 2 2,输入 c为3,可以组成:第一个数(1)与第三个数(2),第一个数(1)与第四个数(3),第二个数(1)与第三个数(2),第二个数(1)与第四个数(2)这四个序列。可是当 1 1 2 2去重之后,变成了1 2,只能组成 1个和为3的序列,与之不匹配,所以,这里要用到神奇的某种数学找规律的思维去推计算公式,例如1 1 1 1 2 2这个序列,去重之后留下了1,2这两个数,1在序列中出现了4次,2在序列中出现了2次,如果要计算1 1 1 1 2 2中能组成几个序列,就将 4(1在序列中出现的次数)*  2(2在序列中出现的次数)。

二分查找函数:

int d(int n,int x) {
	int low=1,high=n;
	while(low<=high) {
		int m=(low+high)/2;
		if(An[m]==x) {
			return m;
		} else if(An[m]<x) {
			low=m+1;
		} else {
			high=m-1;
		}
	}
	return 0;
}//大概是模板的样子

去重操作:

for(int i=1; i<=n; i++) {//这里是去重的操作 
		if(a[i]==a[i-1]) {//判断,如果这个数等于这个数的上一个数,说明重复了。 
			Ak[l]++;//记录l这个数一共出现了几次。 
		} else {//相反,去重后数组的长度 
			l++;
			An[l]=a[i];
			Ak[l]=1;
		}
	}

计算:

for(int i=1; i<=l; i++) {
		int cxk=d(l,An[i]+c);
		if(cxk>0) {//这里需要进行一个特判 
			cnt+=Ak[cxk]*Ak[i];//计算公式 
		}
	}

AC总代吗:

/*                 _ooOoo_
                  o8888888o     
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
#include<bits/stdc++.h>
using namespace std;
int a[200005],An[200005],Ak[200005];
int d(int n,int x) {
	int low=1,high=n;
	while(low<=high) {
		int m=(low+high)/2;
		if(An[m]==x) {
			return m;
		} else if(An[m]<x) {
			low=m+1;
		} else {
			high=m-1;
		}
	}
	return 0;
}
int main() {
	int n,c,l=0,cnt=0;//cnt只是一个计数器,用来计算方案总数 
	scanf("%d%d",&n,&c);
	for(int i=1; i<=n; i++) {
		scanf("%d",&a[i]);//输入要求处理的那串数。 
	}
	sort(a+1,a+n+1);//排序 
	for(int i=1; i<=n; i++) {//这里是去重的操作 
		if(a[i]==a[i-1]) {//判断,如果这个数等于这个数的上一个数,说明重复了。 
			Ak[l]++;//记录l这个数一共出现了几次。 
		} else {//相反,去重后数组的长度 
			l++;
			An[l]=a[i];
			Ak[l]=1;
		}
	}
	for(int i=1; i<=l; i++) {
		int cxk=d(l,An[i]+c);
		if(cxk>0) {//这里需要进行一个特判 
			cnt+=Ak[cxk]*Ak[i];//计算公式 
		}
	}
	printf("%d\n",cnt);//输出方案总数 
	return 0;
}
/*                 _ooOoo_
                  o8888888o     
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值