Acwing 刷题-递增三元组(经典枚举)-爆int了呜呜

递增三元组

给定三个整数数组

A=[A1,A2,…AN],
B=[B1,B2,…BN],
C=[C1,C2,…CN],

请你统计有多少个三元组 (i,j,k) 满足:

1≤i,j,k≤N
Ai<Bj<Ck

输入格式

第一行包含一个整数 N。

第二行包含 N 个整数 A1,A2,…AN。

第三行包含 N 个整数 B1,B2,…BN。

第四行包含 N 个整数 C1,C2,…CN。

输出格式

一个整数表示答案。

数据范围

1≤N≤10^5,
0≤Ai,Bi,Ci≤10^5
输入样例:
3
1 1 1
2 2 2
3 3 3
输出样例:
27

分析:

题干很容易理解,从a,b,c 三个数组种各取一个数满足条件就视为一种情况。如果用暴力来做,就是使用三从循环,时间复杂度将达到O(n^3)当n大于1000时将无法承受。而且此题n最坏情况下还是10 ^5,所以大概猜测一下时间复杂度 为O(nlgn)是程序才可以接受。
然后对做法进行简单的分析:首先一定只能每一一个数组了,所以枚举a,b,c中的那个才能让枚举一次就能确定一种情况呢。。。。
枚举a,c的话理论上是一样的,没办法对离他远的那个进行约束,所以一定是枚举中间的数组b, 对于b中的每一个数字,其他两个从a,c选的数组都会被约束为,小于b[i] 和大于b[i] ,由于对于a,c是相互独立的事件,所以对于每个b【i】 只要从a中找到比他小的(不可以是等于) 数字的个数,和在c中大于b【i】的数字的个数,将二者相乘就是中间数字为b【i】的这种情况的所有情况数量了。
好了,现在思路很清晰了就可以着手写代码了:

code:

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <string>
#include <deque>
using namespace std;
const int maxn=1e5+10;
int n;
long long res=0;
int len;
int a[maxn],b[maxn],c[maxn];
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}for(int i=0;i<n;i++){
		scanf("%d",&b[i]);
	}for(int i=0;i<n;i++){
		scanf("%d",&c[i]);
	}  // 读入a,b,c
	sort(a,a+n);
	sort(c,c+n); //为二分查找做准备
	for(int i=0;i<n;i++){
		int t1,t2;
		int l=0,r=n-1;
		while(l<r){  // 首先在a中查找最后一个小于b[i]的数字位置。
			int mid=(l+r+1)/2;
			if(a[mid]>=b[i]){
				r=mid-1;
			}
			else l=mid;
		}
		t1=l+1;		//a所有满足小于b[i]的数字个数
		if(a[l]>=b[i]) t1=0;
		l=0,r=n-1;
		while(l<r){ // 首先在c中查找第一个大于b[i]的数字位置。
			int mid=(l+r)/2;
			if(c[mid]<=b[i]){
				l=mid+1;
			}
			else r=mid;
		}
		t2=n-l;  //c所有满足大于b[i]的数字个数
		if(c[l]<=b[i]) t2=0;
		res+=(long long )t1*t2; //这里注意了t1和t2 都是int类型的最大都是100000 ,相乘的话可能爆int 所以强转一下。
	}
	cout<<res;
	return 0;
}

没有发现两个int相乘爆int的情况,让我一直无法AC,没办法当时只能用高精度存了res。

Code:

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <string>
#include <deque>
using namespace std;
const int maxn=1e5+10;
int n;
int res[50];
int len;
int a[maxn],b[maxn],c[maxn];
void myfun(long long temp){
	int index=0;
	while(temp){
		res[index]=res[index]+temp%10;
		if(res[index]>=10){
			res[index+1]=res[index+1]+res[index]/10;
			res[index]%=10;
		}
		index++;
		temp/=10;
	}
	len=max(len,index);
}
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
	}for(int i=0;i<n;i++){
		scanf("%d",&b[i]);
	}for(int i=0;i<n;i++){
		scanf("%d",&c[i]);
	}
	sort(a,a+n);
	sort(c,c+n);
	for(int i=0;i<n;i++){
		int t1,t2;
		int l=0,r=n-1;
		while(l<r){
			int mid=(l+r+1)/2;
			if(a[mid]>=b[i]){
				r=mid-1;
			}
			else l=mid;
		}
		t1=l+1;
		if(a[l]>=b[i]) t1=0;
		l=0,r=n-1;
		while(l<r){
			int mid=(l+r)/2;
			if(c[mid]<=b[i]){
				l=mid+1;
			}
			else r=mid;
		}
		t2=n-l;
		if(c[l]<=b[i]) t2=0;
		myfun((long long)t1*t2);
	}
	if(res[len]==0) len-=1;
	for(int i=len;i>=0;i--){
		cout<<res[i];
	}
	if(len==-1) cout<<0;
	cout<<endl;
}

用了大整数加法后,依然是无法AC 这是才发现了问题的真正所在,哎,很难受就是了,以后一定注意呜呜呜。

两个10^5 的int相乘将可能爆int ,用long long 强转,或者直接将两数定义为long long即可。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值