USACO20Jan Farmer John Sovles 3SUM G 【动态规划】
为什么我在自己思考的时候做不出来这题:
- 没有考场的环境,不是很显然的题就开始想看题解
- 想过dp,但是没有认真的想就认为不能用dp,因为这样需要O(1)转移,然而正解就是O(1)转移,以后做题目时,如果考虑dp就需要把状态和转移都列出来,确认实在无法优化后再放弃(但是一般如果只是因为时间复杂度的话一般都需要继续优化)
其实挺简单的这题,直接区间dp,转移为dp[i][j] = dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1] + calc[i][j],其中calc表示确定选了i, j这两个点后,i到j之间有几个满足条件的点,可以N方算出
dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]表示强制选i, j中的其中一个的方案数,[i + 1,j - 1]重复了需要减掉
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define gi get_int()
const int MAXN = 5001, LIM = 2e6 + 1, ADD = 2e6;
int get_int()
{
int x = 0, y = 1;
char ch = getchar();
while (!isdigit(ch) && ch != '-')
ch = getchar();
if (ch == '-')
y = -1, ch = getchar();
while (isdigit(ch))
x = x * 10 + ch - '0', ch = getchar();
return x * y;
}
long long dp[MAXN][MAXN];
int cnt[LIM * 2], num[MAXN];
signed main()
{
freopen("code.in", "r", stdin);
freopen("code.out", "w", stdout);
int n = gi, Q = gi;
for (int i = 0; i < n; i++)
num[i] = gi;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
dp[i][j] = j == i ? 0 : cnt[ADD - (num[i] + num[j])];
cnt[num[j] + ADD]++;
}
for (int j = i + 1; j < n; j++)
cnt[num[j] + ADD]--;
}
for (int size = 3; size <= n; size++) {
for (int i = 0; i <= n - size; i++) {
int j = i + size - 1;
dp[i][j] = dp[i][j - 1] + dp[i + 1][j] - dp[i + 1][j - 1] + dp[i][j];
}
}
while (Q--) {
int l = gi - 1, r = gi - 1;
std::cout << dp[l][r] << std::endl;
}
return 0;
}

浙公网安备 33010602011771号