&最长上升子序列
3 4 1 5 2 7 6
dfs(int i, int j, int len)
表示前i的位置,以a[j]为结尾的最长上升子序列长度为len
dfs(i+1, a[j], len)
dfs(i+1, a[i+1], len+1)
dp[i][len] 前i个元素,组成长度为len的lis序列,对应的结尾数字的最小值
g[i]//表示最长上升长度为i时,最小的数值
例如:
1 8 6 10 7
g[1] = 1
g[2] = 8->6
g[3] = 10->7
for(int i = 1; i <= n; i++){
a[i] 和前面所有值比较
}
&树状数组求顺序对,-_-!
3 4 1 5 2 7 6
1 2 3 4 5 6 7
0 从1-2没有被标记的
1 从1-3找有几个数字标记了
0 从1-0
3 从1-4有三个标记了
1 从1-1有一个标记了
5 从1-6有5个标记了
5 从1-5有5个标记了
加在一起,可以得到顺序对的个数
&树状数组求最长上升子序列
3 4 1 5 2 7 6
1 2 3 4 5 6 7
1
2
1
3 从1-4找最大值
2
4
4
&最长公共子序列
暴力:dfs(i,j,len)
dp[i][len] 表示第一串前i位置,构成lcs时,第二串的最小位置
#include <bits/stdc++.h>
using namespace std;
string sa, sb;
int loc[200][500005], res, num[200], dp[1005][1005], mx = 0x3f3f3f3f;
int find(char x, int n, int cp) {
int l = 1, r = n, ans = mx;
while (l <= r) {
int mid = (l + r) >> 1;
if (loc[x - 'a'][mid] > cp) { //找最小的位置
r = mid - 1;
ans = mid;
} else
l = mid + 1;
}
if (ans == mx)
return mx;
else
return loc[x - 'a'][ans];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> sa >> sb;
int la = sa.size(), lb = sb.size();
for (int i = 0; i < lb; i++) {
loc[sb[i] - 'a'][++num[sb[i] - 'a']] = i;
// cout<<sb[i]<<" "<<num[sb[i]-'a']<<" "<<loc[sb[i]-'a'][num[sb[i]-'a']]<<endl;
}
memset(dp, 0x3f, sizeof dp);
for (int i = 0; i < la; i++) dp[i][0] = -1; //所有的len=1,都是可以找的
for (int i = 0; i < la; i++) {
for (int len = 1; len <= i + 1; len++) { //公共子序列的长度
int val;
if (i == 0) {
val = find(sa[i], num[sa[i] - 'a'], -1);
}
// else if(dp[i-1][len-1] == mx) pos = mx; //dp[4][3] = mx, error, dp[4][3] = min(dp[i][3])
else {
val = find(sa[i], num[sa[i] - 'a'], dp[i - 1][len - 1]);
}
// if(pos == mx)
// dp[i][len] = mx;
// else
dp[i][len] = (i != 0 ? min(dp[i - 1][len], val) : val); //达到这个长度,最小的位置
// cout<<"ttt: "<<sa[i]<<" "<<i<<" "<<len<<" "<<val<<" "<<dp[i][len]<<endl;
res = max(res, dp[i][len] != mx ? len : 0); //答案
}
}
cout << res << endl;
return 0;
}
/*
mrhnobtxjawybtyvz
ntcjumuvztkgbpgwscpawj
mrjujz
rcmjruzt
ntcjumuvztkgbpgwscpawjvfksvgzisarblzqcsg
mrhnobtxjawybtyvzfiiupiwgzbzyunrdvijmdgvciharilvcne
*/