OJ-Problems-Source/.ACM-Templates/动态规划.cpp
2016-08-13 23:07:20 +08:00

273 lines
8.7 KiB
C++

//最大子段和 O(n)
ll maxSum(int a[], int n, int &st, int &ed) {
ll mx = a[0], mxc = 0; st = ed = 0;
for (int i = 1; i < n; i++) {
if (mxc > 0) { mxc += a[i]; }
else { mxc = a[i]; s = i; }
if (mxc > mx) { mx = mxc; st = s; ed = i; }
}
return mx;
}
//循环数组最大子段和 O(n)
const ll INF = 0x7f7f7f7f7f7fLL;
ll maxSum_adj(int a[], int n) {
ll mx = -INF, mxc = 0, mn = INF, mnc = 0, sum = 0;
for (int i = 0; i < n; i++) {
mxc = a[i] + (mxc > 0 ? mxc : 0);
if (mx < mxc) { mx = mxc; }
mnc = a[i] + (mnc > 0 ? 0 : mnc);
if (mn > mnc) { mn = mnc; }
sum += a[i];
}
return mx < 0 || mx > sum - mn ? mx : sum - mn;
}
//最大M子段和 O(nm)
ll dp[N], mxsum[N];
ll mxMSum(int a[], int n, int m) {
ll mx;
for (int i = 1; i <= m; i++) {
mx = 0x8f8f8f8f8f8f8f8fLL;
for (int j = i; j <= n; j++) {
dp[j] = max(dp[j - 1], mxsum[j - 1]) + a[j];
mxsum[j - 1] = mx; mx = max(mx, dp[j]);
}
}
return mx;
}
//最大子阵和 O(n^3)
ll presum[N][N];
ll maxSum(int a[][N], int h, int w, int &x1, int &y1, int &x2, int &y2) {
ll ret = a[0][0], sum; x1 = y1 = x2 = y2 = 0;
for (int i = 0; i < h; i++) {
presum[i][0] = 0;
for (int j = 0; j < w; j++) { presum[i][j + 1] = presum[i][j] + a[i][j]; }
}
for (int j = 0; j < w; j++) {
for (int k = j, s; k < w; k++) {
sum = s = 0;
for (int i = 0; i < h; i++, s = sum > 0 ? s : i) {
if ((sum = (sum > 0 ? sum : 0) + presum[i][k + 1] - presum[i][j]) > ret) {
ret = sum; x1 = s; y1 = j; x2 = i; y2 = k;
}
}
}
}
return ret;
}
//最长上升子序列 Longest Increasing Subsequence O(nlogn)
int b[N];
int LIS(int a[], int n) {
int len = 1; b[0] = a[0];
for (int i = 1; i < n; i++) {
b[a[i] > b[len - 1] ? len++ : lower_bound(b, b + len, a[i]) - b] = a[i]; //非降换为>=和upper_bound
}
return len;
}
//最长上升子序列数量 O(nlogn)?
int b[N], l[N]; ll cnt[N];
vector<int> v[N];
ll LIS(int a[], int n) {
int len = 1; b[0] = a[0]; l[0] = 1; v[1].push_back(0);
for (int i = 1; i < n; i++) {
int pos = a[i] > b[len - 1] ? len++ : lower_bound(b, b + len, a[i]) - b;
b[pos] = a[i]; l[i] = pos + 1;
v[l[i]].push_back(i);
}
ll ret = 0;
for (int i = 0; i < n; i++) {
if (l[i] == 1) { cnt[i] = 1; continue; }
for (int j = 0, ll = l[i] - 1; j < (int)v[ll].size() && v[ll][j] <= i; j++) {
if (a[v[ll][j]] < a[i]) { cnt[i] += cnt[v[ll][j]]; }
}
if (l[i] == len) { ret += cnt[i]; }
}
return ret;
}
//长度为k的上升子序列个数 O(knlogn)
int n, k;
ll bit[M][N];
inline int lowbit(int x) { return x & -x; }
void add(int id, int i, ll val) { while (i <= n) { bit[id][i] += val; i += lowbit(i); } }
ll sum(int id, int i) { ll ret = 0; while (i) { ret += bit[id][i]; i -= lowbit(i); } return ret; }
int main() {
scanf("%d%d", &n, &k);
add(0, 1, 1);
for (int i = 1, x; i <= n; i++) {
scanf("%d", &x);
for (int j = 1; j <= k; j++) { add(j, x, sum(j - 1, x - 1)); } //非降改为x
}
printf("%I64d\n", sum(k, n)); //n为元素最大值
}
//最长公共子序列 Longest Common Subsequence O(n^2)
int dp[N][N];
int LCS(char *a, char *b) {
int m = strlen(a), n = strlen(b);
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (a[i - 1] == b[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; }
else { dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); }
}
}
return dp[m][n];
}
void printLCS(char *a, char *b) {
char s[N] = {0};
for (int i = strlen(a), j = strlen(b), k = dp[i][j]; i && j;) {
if (a[i - 1] == b[j - 1] && dp[i][j] == dp[i - 1][j - 1] + 1) { s[--k] = a[--i]; --j; }
else if (dp[i - 1][j] > dp[i][j - 1]) { i--; }
else { j--; }
}
puts(s);
}
//最长公共子串 Longest Common Substring
//DP O(n^2)
int dp[2][N];
int LCS_dp(char *a, char *b, int &st1, int &st2) {
int m = strlen(a), n = strlen(b), ret = 0, cur = 0; st1 = st2 = -1;
for (int i = 0; i < m; i++, cur ^= 1) {
for (int j = 0; j < n; j++) {
if (a[i] == b[j]) {
dp[cur][j] = i == 0 || j == 0 ? 1 : dp[cur ^ 1][j - 1] + 1;
if (dp[cur][j] > ret) { ret = dp[cur][j]; st1 = i + 1 - ret; st2 = j + 1 - ret; }
}
}
}
//outputLCS(a, ret, st1);
return ret;
}
//后缀数组 O(nlogn)
char *suf[N];
int pstrcmp(const void *p, const void *q) {
return strcmp(*(char **)p, *(char **)q);
}
int comlen_suf(const char *p, const char *q) {
for (int len = 0; *p && *q && *p++ == *q++;) {
len++;
if (*p == '#' || *q == '#') { return len; }
}
return 0;
}
int LCS_suffix(char *a, char *b) {
int m = strlen(a), n = strlen(b), ret = 0, suf_index = 0, len_suf = m + n + 1;
char *arr = new char[len_suf + 1];
strcpy(arr, a); arr[m] = '#'; strcpy(arr + m + 1, b);
for (int i = 0; i < len_suf; i++) { suf[i] = &arr[i]; }
qsort(suf, len_suf, sizeof(char *), pstrcmp);
for (int i = 0; i < len_suf - 1; i++) {
int len = comlen_suf(suf[i], suf[i + 1]);
if (len > ret) { ret = len; suf_index = i; }
}
//outputLCS(suf[suf_index], ret);
delete[] arr; return ret;
}
void outputLCS(char *s, int len, int i = 0) {
for (; len--; i++) { putchar(s[i]); } puts("");
}
//DP 下界O(nlogn) 上界O(nmlog(nm))
int c[N * N], d[N * N];
int LCS_dp(char *a, char *b) {
vector<int> pos[26]; int k = 0, len = 1; d[0] = c[0];
for (int i = strlen(b) - 1; i >= 0; i--) { pos[b[i] - 'a'].push_back(i); }
for (int i = 0; a[i]; i++) {
for (int j = 0; j < (int)pos[a[i] - 'a'].size(); j++) { c[k++] = pos[a[i] - 'a'][j]; }
}
for (int i = 1; i < k; i++) {
d[c[i] > d[len - 1] ? len++ : lower_bound(d, d + len, c[i]) - d] = c[i];
}
return len;
}
//最长公共递增子序列 GCIS O(n^2)
int dp[N], f[N][N];
int GCIS(int a[], int la, int b[], int lb, int ans[]) {
//a[1...la], b[1...lb]
int mx = 0;
memset(f, 0, sizeof(f));
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= la; i++) {
memcpy(f[i], f[i - 1], sizeof(f[0]));
for (int j = 1, k = 0; j <= lb; j++) {
if (a[j - 1] > b[i - 1] && dp[k] < dp[j]) { k = j; }
if (b[j - 1] == a[i - 1] && dp[k] + 1 > dp[j]) { dp[j] = dp[k] + 1; f[i][j] = i * (lb + 1) + k; }
}
}
for (int i = 1; i <= lb; i++) { if (dp[i] > dp[mx]) { mx = i; } }
for (int i = la * lb + la + mx, j = dp[mx]; j; i = f[i / (lb + 1)][i % (lb + 1)], j--) {
ans[j - 1] = b[i % (lb + 1) - 1];
}
return dp[mx];
}
//字符串编辑距离 (Levenshtein距离)
//操作包括将替换一个字符, 插入一个字符, 删除一个字符
int dp[N][N];
int LevDist(char *a, char *b) {
int n = strlen(a), m = strlen(b);
for (int i = 0; i <= n; i++) { dp[i][0] = i; }
for (int i = 0; i <= m; i++) { dp[0][i] = i; }
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1;
if (a[i - 1] == b[j - 1]) { dp[i][j] = min(dp[i][j], dp[i - 1][j - 1]); }
else { dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1); }
}
}
return dp[n][m];
}
//字符串距离
//非空格字符的距离定义为它们的ASCII码的差的绝对值, 空格字符与其它任意字符之间的距离为已知的定值k
int dp[N][N];
int dist(char *a, char *b, int k) {
int n = strlen(a), m = strlen(b);
for (int i = 0; i <= n; i++) { dp[i][0] = i * k; }
for (int i = 1; i <= m; i++) { dp[0][i] = i * k; }
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = min(dp[i - 1][j - 1] + abs(a[i - 1] - b[j - 1]), min(dp[i - 1][j], dp[i][j - 1]) + k);
}
}
return dp[n][m];
}
//TSP问题 O(V^2*2^V)
int n, mp[N][N], dp[1 << N][N];
int TSP() {
memset(dp, 0x1f, sizeof(dp));
dp[1][0] = 0;
for (int s = 0; s < 1 << n; s++) {
for (int v = 0; v < n; v++) {
if (dp[s][v] == 0x1f1f1f1f) { continue; }
for (int u = 0; u < n; u++) {
if (s & 1 << u) { continue; }
dp[s | 1 << u][u] = min(dp[s | 1 << u][u], dp[s][v] + mp[v][u]);
}
}
}
int ans = 0x1f1f1f1f;
for (int i = 0; i < n; i++) { ans = min(ans, dp[(1 << n) - 1][i] + mp[i][0]); }
return ans;
}
//mTSP问题 O(V^2*2^V)
int n, mp[N][N], dp[1 << N][N], best[1 << N];
bool ok[1 << N]; //该集合状态是否可行
int mTSP() {
memset(dp, 0x1f, sizeof(dp));
memset(best, 0x1f, sizeof(best));
dp[1][0] = 0;
for (int s = 0; s < 1 << n; s++) {
if (!ok[s]) { continue; }
for (int v = 0; v < n; v++) {
if (!(s & (1 << v)) || dp[s][v] == 0x1f1f1f1f) { continue; }
best[s] = min(best[s], dp[s][v] + mp[v][0]);
for (int u = 0; u < n; u++) {
if (s & (1 << u)) { continue; }
dp[s | 1 << u][u] = min(dp[s | 1 << u][u], dp[s][v] + mp[v][u]);
}
}
}
for (int s = 0; s < 1 << n; s++) {
if (!(s & 1)) { continue; }
for (int i = s & (s - 1); i; i = s & (i - 1)) {
best[s] = min(best[s], best[i] + best[(s ^ i) | 1]);
}
}
return best[(1 << n) - 1];
}