给你一个长度为n的序列A,你需要算出有多少个三元组(Ai,Aj,Ak)满足i<j<k且AiAj
Ak。
给你一个长度为n的序列A,你需要算出有多少个三元组(Ai,Aj,Ak)满足i<j<k且AiAj
Ak。
第一行一个整数n,表示序列A的长度。
接下来一行n个整数,第i个数表示Ai的值。
一个整数x,表示满足要求的三元组数量。
6 2 3 5 4 3 3
6
第1个数据为样例。
第2~4个数据范围:
n<=500,Ai<=1000000
第5~7个数据范围:
n<=2000,Ai<=1000000
第8~10个数据范围:
n<=100000,Ai<=1000000
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
ArrayList<Integer> used = new ArrayList<>(); // 已使用数据
ArrayList<Integer> standby = new ArrayList<>(); // 待使用数据
int[] arr = new int[n + 1];
for(int i = 0; i < n; i++) {
arr[i + 1] = sc.nextInt();
if(i == 0)
used.add(arr[i + 1]);
else
standby.add(arr[i + 1]);
}
Collections.sort(standby);
long res = 0L;
for(int i = 2; i <= n; i++){
// 以arr[i]作为中间数
int minIdx = upper_bound(used, arr[i]); // 从小索引的数据中找到第一个大于arr[i]的位置
int maxIdx = lower_bound(standby, arr[i]); // 从大索引的数据中找到第一个大于等于arr[i]的位置
long count1 = minIdx; // minIdx前面的数都可以作为三元组的最小数
long count2 = standby.size() - maxIdx - 1; // maxIdx后面的数都可以作为三元组的最大数
res += count1 * count2; // 累加上以arr[i]为中间数时的三元组数
used.add(minIdx, arr[i]);
standby.remove(maxIdx);
}
System.out.println(res);
}
private static int lower_bound(ArrayList<Integer> list, int target) {
int left = 0;
int right = list.size() - 1;
int res = right + 1;
while(left <= right){
int mid = (left + right) >> 1;
if(list.get(mid) >= target){
right = mid - 1;
res = mid;
}else{
left = mid + 1;
}
}
return res;
}
private static int upper_bound(ArrayList<Integer> list, int target) {
int left = 0;
int right = list.size() - 1;
int res = right + 1;
while(left <= right){
int mid = (left + right) >> 1;
if(list.get(mid) > target){
right = mid - 1;
res = mid;
}else{
left = mid + 1;
}
}
return res;
}
}
import java.io.*;
public class Main{
public static void main(String[] args) throws Exception {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int n= Integer.parseInt(br.readLine());
int[] arr=new int[n];
String[] sp=br.readLine().split(" ");
for (int i = 0; i <n ; i++) {
arr[i]=Integer.parseInt(sp[i]);
}
int ans= process(3,0,Integer.MAX_VALUE,arr);
System.out.println(ans);
}
public static int process(int rest , int i , int preChose , int[] arr){
if (rest==0){
return 1;
}
if (i>=arr.length){
return 0;
}
if (preChose!=Integer.MAX_VALUE&& preChose>arr[i]){
return 0;
}
int res=0;//返回的答案
int p1=process(rest-1,i+1,arr[i],arr);
int p2=process(rest,i+1,preChose,arr);
res=p1+p2;
return res;
}
}
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll n,ans=0,a[100005],dp[100005];
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int i,j;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];
for(j=i-1;j>=1;j--)
{/**<暴力检查a[i]左侧有多少个比a[i]小的,这个数字记录在dp[i],
dp存储的是以i为的第二个元素的二元组个数 */
if(a[j]<=a[i])
dp[i]++,ans+=dp[j];/**< 顺路计算a[i]左侧a[j]的二元组,这些二元组和a[i]可以构成三元组 */
}
}
cout<<ans;
return 0;
}
可优化的就是内层循环,由于题目ai数据范围为1000000,考虑用树状数组存储和查询比a[i]小元素个数,用另一个树状数组存储二元组个数. #include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll n,t1[1000005],t2[1000005],ans=0,a[100005];
void add1(int x,int y)
{
for(;x<=1000000;x+=x&-x)
t1[x]+=y;
}
ll get1(int x)
{
ll an=0;
for(;x;x-=x&-x)
an+=t1[x];
return an;
}
void add2(int x,int y)
{
for(;x<=1000000;x+=x&-x)
t2[x]+=y;
}
ll get2(int x)
{
ll an=0;
for(;x;x-=x&-x)
an+=t2[x];
return an;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int i,j;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];/**< a1为a[i]左侧不大于它的元素个数,a2为a[i]左侧二元组的个数 */
ll a1=get1(a[i]),a2=get2(a[i]);
add2(a[i],a1);/**< a1个元素和a[i]构成二元组,存储到t2数组 */
add1(a[i],1);/**< 把a[i]值存储在t1数组,用于后序查询 */
ans+=a2;
}
cout<<ans;
return 0;
}
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
LinkedList<Integer> trank = new LinkedList<>();
int[] nums = new int[n];
for (int i = 0; i < n; i++)
nums[i] = in.nextInt();
backtrank(nums,0,trank);
System.out.println(res);
}
static int res = 0;
static void backtrank(int[] nums, int start,LinkedList<Integer> trank){
if((trank.size() + nums.length - start ) < 3)
return;
if(trank.size() == 2){
if(trank.get(0) > trank.get(1))
return;
}
if(trank.size() == 3) {
if (trank.get(0) <= trank.get(1) && trank.get(1) <= trank.get(2)) {
res++;
}
return;
}
if(trank.size() > 3)
return;
for (int i = start; i < nums.length; i++) {
trank.addLast(nums[i]);
backtrank(nums,i + 1,trank);
trank.removeLast();
}
}
}
超时了 只会回溯的方法 后面的用例太大了
#include <iostream>
#include <vector>
using namespace std;
struct Data{
//值
int val;
//左边比他小的
int lsmall;
//右边比他大的
int rbig;
Data():val(0), lsmall(0), rbig(0){}
};
void merge(vector<Data> &v, int l, int m, int r){
int i = l, j = m + 1;
vector<Data> help(r - l + 1);
int small = 0;
int index = 0;
while (i <= m && j <= r){
if (v[i].val <= v[j].val){
v[i].rbig += (r - j + 1);
help[index++] = v[i];
++i;
++small;
}else{
v[j].lsmall += small;
help[index++] = v[j];
++j;
}
}
while (i <= m){
help[index++] = v[i++];
}
while (j <= r){
v[j].lsmall += small;
help[index++] = v[j];
++j;
}
for (index = 0; index < (int)help.size();){
v[l++] = help[index++];
}
}
void f(vector<Data> &v, int l, int r){
if (l >= r){
return;
}
int mid = l + ((r - l) >> 1);
f(v, l, mid);
f(v, mid + 1, r);
merge(v, l, mid, r);
}
void f(vector<Data> &v){
if (v.size() < 2){
return;
}
f(v, 0, v.size() - 1);
}
using ll = long long;
int main(){
int n;
cin >> n;
vector<Data> v(n);
for (int i = 0; i < n; ++i){
cin >> v[i].val;
}
f(v);
ll ans = 0;
for (Data elem : v){
ans += (ll)elem.lsmall * elem.rbig;
}
cout << ans << endl;
return 0;
}