2020-10-31
dp
977F 1700
题目
原题链接:https://codeforces.com/problemset/problem/977/F
思路
题目大意:给定一个整数数组a,在里面找一个最长的子序列,子序列满足每一项都比且只比前一项大1,即[x,x+1,…,x+k−1]。要求给出最长子序列的长度以及对应的子序列
思路:这道题我做的真的是一波三折折折折折折。
首先看到题就应该知道这道题是求最长上升子序列。
然后我直接打了个模板,在状态转换的时候用了两个for去做,如下
for(int i = 1; i <= n; i++)
for(int j = i-1;j ; j--){
........
}
然后直接第8个用例TLE
然后我又改成用map数组去存储每个数在原数组中的索引,如下
map<int, vector<int>> mp;
a[i] = read();
mp[a[i]].push_back(i);
if (mp.find(tp) != mp.end()) {
int len = mp[tp].size();
for (int j = len - 1; j >= 0; j--) {
if (mp[tp][j] < i) {
dp[i] = dp[mp[tp][j]] + 1;
pre[i] = mp[tp][j];
goto OUT;
}
}
}
这个一开始很顺利,但还是在第33个样例再次TLE,数据量是2e5,之前的2e5都过了,这个用例又来卡人了。
200000
1 2 1 2 1 2 1 2 1 2 .......................//就是这样无限重复下去
然后,无计可施之下只能加了个快读,依旧没卵用,卡的就是状态转换的那一段。
最后实在没得法了,只能开启面向百度编程大法,哈哈哈哈哈哈哈哈哈。
然后发现本题的重点是看出前一个状态是确定的,直接map做!
就是去考虑 : 当我们现在拿到一个数a时,我们一定是去a找前面第一个a-1的时候的值,也只跟这个a-1的位置有关。
所以我们直接拿map做就好了,映射数值和长度,即拿到数a,那我们求的状态就是dp[a],然后我们直接找dp[a-1]
即可,因为是字典哈希,这个拿值是O1的复杂度,至此终于将状态转换的部分的复杂度降下来了。
这几题都是在回来的火车上敲的,同车的大佬还跟我讲了一种最长上升子序列nlogn的做法,可以去洛谷搜一下导弹拦截那道题。这里用不着那么做就不展开了。
代码实现
TLE款
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <string>
using namespace std;
#define mes0(c) memset((c),0,sizeof(c))
#define fsios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define rep(n) for(int i=1;i<=(n);i++)
#define inp(a, n) for (int i = 1; i <= (n); i++) cin >> a[i];
#define ll long long
#define fi first
#define se second
const ll MAX = 2e5 + 5;
const ll ifi = 1e6 + 5;
int n;
int a[MAX], pre[MAX];
int dp[MAX], ans[MAX];
map<int, vector<int>> mp;
namespace IO {
inline int read() {
int x <