继续撸题!
一、题目大意
题目的大致意思是,给你 n 个数字序列,要求你对其中的序列进行任意组合,求组合后满足有一个上升的条件的组合数有多少种(可以自身和自身组合)
关于有一个上升的条件,就是在序列中存在一对数ai,aj,如果 i > j 的话,那么,ai > aj,注意,存在一对即可。
二、题目思路以及AC代码
这题大体思路如下,其实就考察数据结构建立以及二分,当然我会后面证明它数据水,不二分也可以过,嘿嘿。
关于这道题,我们首先要考虑,什么样的组合可以满足条件?题目已经告诉你是两个序列的组合,那么组合后满足条件,无非是以下两种情况。
① 组合前其中某一个就有一个上升条件,那么组合后自然满足条件。
② 如果组合前的两个序列均不满足上升条件,那么组合时,如果前一个序列的最小值小于后一个序列的最大值,那么组合后也一定满足条件。
当然这里需要考虑一下这两者是否有冲突。我们可以这样考虑,全部的解空间应该是一个 n×n 的矩阵,代表序列的两两组合。
第一种情况,如果组合前某一个满足,那组合后一定满足,也就是如下图所示的黑色部分。
这里就需要注意,在统计个数的时候,首先每次要加的 2n - 1,除此之外,再非第一次加入的时候,要额外减去之前已经加过的,也就是 2num(这里自己去考虑吧)
第二种情况,就是考虑那个序列可以在哪个序列的后面,这部分要在前面的序列排除的基础上进行处理,如下图,就代表了第i个序列的最大值大于前j的序列的最小值,所以可以满足。
以上,就是整道题的思路,虽然是道B题,可是还挺麻烦的。
然后关于时间复杂度的问题,当你实际去考虑编程的时候,你就会发现时间大都浪费在第二种情况,就是找某个序列的最大值比多少个序列的最小值大。这里可以考虑用二分,也可以不用,我的代码里面也都给出了。
值得一提的是,这里数据比较水,但我好像也比较巧,不用二分的时间花费是1996ms,要求2000ms,刚好满足,哈哈哈,但二分自然就快的多了,296ms,下面给出AC代码:
/*
* Codeforce 1284B
* @Author: Johnson
* @Date: 2020.1.5
*/
#include <iostream>
#include <string.h>
#include <cstring>
#include <algorithm>
#define MAXN 100010
#define INF 10000000
using namespace std;
struct Sequence {
int max;
int min;
bool is_ascent;
};
Sequence sequences[MAXN];
Sequence s[MAXN];
bool vis[MAXN];
void init() {
for (int i=0;i<MAXN;i++) {
vis[i] = false;
}
}
bool cmp(Sequence a, Sequence b) {
return a.min < b.min;
}
// 二分
int findPos(int left, int right, int x) {
if (left > right) return left;
int mid = static_cast<int>((left + right) / 2);
if (s[mid].min >= x) return findPos(left, mid - 1, x);
else return findPos(mid + 1, right, x);
}
// 非二分
/*int findPos(int left, int right, int x) {
for (int i=left;i<=right;i++) {
if (x <= s[i].min) {
return i;
}
}
return right + 1;
}*/
int main() {
int n;
cin >> n;
for (int i=0;i<n;i++) {
int len;
cin >> len;
int temp;
cin >> temp;
int t_max = temp;
int t_min = temp;
for (int j=1;j<len;j++) {
cin >> temp;
if (temp > t_min) {
sequences[i].is_ascent = true;
vis[i] = true;
}
if (temp < t_min) t_min = temp;
if (temp > t_max) t_max = temp;
}
sequences[i].min = t_min;
sequences[i].max = t_max;
}
long long ans = 0;
int num = 0;
for (int i=0;i<n;i++) {
if (vis[i]) {
ans += ((2*n - 1) - 2*num);
num++;
}
}
int idx = 0;
for (int i=0;i<n;i++) {
if (!vis[i]) s[idx++] = sequences[i];
}
sort(s, s+idx, cmp);
for (int i=0;i<idx;i++) {
ans += findPos(0, idx - 1, s[i].max);
}
cout << ans << endl;
// system("pause");
return 0;
}
如果有问题,欢迎大家留言!!!