题目描述
题目看多了也有审美疲劳,于是我舍弃了大家所熟悉的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
____/`---'\____
.' \\| |// `.
/ \\||| : |||// \
/ _||||| -:- |||||- \
| | \\\ - /// | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . __
."" '< `.___\_<|>_/___.' >'"".
| | : `- \`.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
======`-.____`-.___\_____/___.-`____.-'======
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/