CF1005D Polycarp and Div 3
本题标签是贪心、字符串和前缀和,但是最重要的是动态规划。
我们考虑设 表示前 个字符最多段数,很显然我们枚举 从 到 ,对于每个 求一次数字和,如果为 就对贡献加 。
但是很明显这个复杂度是 ,妥妥 TLE。这时,数学就登场了。
我们知道任一自然数除以 余数可能为 。从反面考虑,我们尽量让若干个数相加仍然不是 的倍数。明显,我们尽量让余数为 的不出现。那么 ,,可得,任取 个自然数,其中必有连续的若干个数的和是 的倍数。
因此,可以将 的枚举范围变为 ,代码实现:
#include <string>
#include <iostream>
using namespace std;
#define int long long
const int N = 2e5 + 5;
int dp[N], pre[N], ans = 0;
string s;
signed main()
{
cin >> s;
int len = s.size(), ans = 0;
for (int i = 1; i <= len; i++) pre[i] = pre[i - 1] + (s[i - 1] - '0');
for (int i = 1; i <= len; i++)
{
for (int j = i; j >= i - 2; j--)
{
if (j < 1) break;
int x = pre[i] - pre[j - 1];
dp[i] = max(dp[i], dp[j - 1] + (x % 3 == 0 ? 1 : 0));
}
ans = max(ans, dp[i]);
}
cout << ans << endl;
return 0;
}