给定一个长度为 NN 的数组 A=[A_1, A_2, … A_N]A=[A
1
,A
2
,…A
N
],已知其中每个元素 A_iA
i
的值都只可能是 1, 21,2 或者 33。
请求出有多少下标三元组 (i, j, k)(i,j,k) 满足 1 \le i < j < k \le N1≤i<j<k≤N 且 A_i < A_j < A_kA
i
<A
j
<A
k
。
输入格式
第一行包含一个整数 NN;
第二行包含 NN 个整数 A_1, A_2, … A_NA
1
,A
2
,…A
N
。(1 \le A_i \le 3, 1 \le N \le 100000(1≤A
i
≤3,1≤N≤100000)。
输出格式
一个整数表示答案。
输出时每行末尾的多余空格,不影响答案正确性
样例输入复制
6
1 3 2 1 2 3
样例输出复制
3
本题刚开始已看感觉可以用dp完成,于是就试了一下,结果就过了两个case,超时了,后来查了一下,发现一种更巧妙的方法,控制在o(n)的时间之内完成,佩服
这是dp版本的,超时…
//@author:hairu,wu
//@from:ahut
#include<iostream>
using namespace std;
const int max_n=100001;
int a[max_n];
int dp[max_n];
int main(){
int n;
cin >> n;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
if(a[i]==1) dp[i]=1;
else dp[i]=0;
}
//dp[i]表示的是以i结尾的符合条件的种数
for(int i=0;i<n;i++){
if(a[i]==1) continue;
for(int j=0;j<i;j++){
if(a[i]==a[j]+1){
dp[i]=dp[i]+dp[j];
}
}
}
cout<<dp[n-1]<<endl;
return 0;
}
巧妙版的
//@author:hairu,wu
//@from:ahut
#include<iostream>
using namespace std;
typedef long long ll;
const int max_n=101000;
int a[max_n];
int main(){
int n;
cin >> n;
ll t1=0,t3=0;
for(int i=0;i<n;i++){
cin >>a[i];
if(a[i]==3){
t3++;
}
}
ll cnt=0;
for(int i=0;i<n;i++){
if(a[i]==1){
t1++;
}
else if(a[i]==2){
cnt+=t1*t3;
}
else if(a[i]==3){
t3--;
}
}
cout<<cnt<<endl;
return 0;
}