https://codeforces.com/contest/1320/problem/A
题意:给定n个数的数组a,现要构造数组,要求构造的数组所使用的a中元素的下标[ci, ci + 1, ...],c[i + 1] - c[i] = a[c[i + 1]] - a[c[i]],问所有符合条件的可构造出来的数组中,和最大是多少?
思路:c[i + 1] - c[i] = a[c[i + 1]] - a[c[i]],在物理上可解释为:经过一定长度的距离变化后,可以推测出变化的数值是多少;在数学上,也可以转化为:c[i + 1] - a[c[i + 1]] = c[i] - a[c[i]]。那么就直接红黑树一次遍历数组a即可。
总结:自己想只想到了暴力,看了solution的第一句话后恍然大悟,只要做一个公式变换就行。但是如果不是刻意往这个方面想的话,其实很难想到这种思路。 如果从物理意义上解释,我觉得更好理解一点。 构造出来的数组,c[i] 和 c[i + 1]的距离可能不是固定的,但是它们的变化比率是一定的,假如之前的下标变化长度为3,数值变化了6,那么下一个下标变化长度为5时,则数值变化应该为6 / 3 * 5 = 10。所以说,每个数跟它所在的位置有一个基数,这个基数是相等的。
顺便放一下耻辱的暴力解法:
inline void solve() {int n;cin >> n;vector<int> b(n);vector<int> dp(n, 0);for (int i = 0; i < n; ++i) {cin >> b[i];dp[i] = b[i];}for (int i = 0; i < n; ++i) {for (int j = i - 1; j >= 0; --j) {if (i - j == b[i] - b[j]) {dp[i] = max(dp[i], dp[j] + b[i]);}}}cout << *max_element(dp.begin(), dp.end()) << '\n';}
正解:
inline void solve() {int n;cin >> n;map<int, long long> mapp;long long ans = 0;for (int i = 0; i < n; ++i) {int x;cin >> x;mapp[x - i] += x;ans = max(ans, mapp[x - i]);}cout << ans << '\n';
}