[CF792C] Divide by Three - dp
Description
有一个正整数串写在黑板上。 你需要通过删除一些位使得他变成一个不含前导 0 且是 3 的倍数,并且需要删除尽量少的位数。
Solution
设 (f[i][j]) 表示以 (i) 为结尾的子序列,值 (mod 3=j),最大长度是多少
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5;
int f[N][3], p[N][3], n, a[N];
signed main()
{
ios::sync_with_stdio(false);
string str;
cin >> str;
n = str.length();
for (int i = 1; i <= n; i++)
a[i] = str[i - 1] - '0';
memset(f, -0x3f, sizeof f);
for (int i = 1; i <= n; i++)
if (a[i])
f[i][a[i] % 3] = 1, p[i][a[i] % 3] = -1;
for (int i = 1; i <= n; i++)
{
for (int j = 0; j < 3; j++)
{
f[i][j] = max(f[i][j], f[i - 1][j]);
f[i][j] = max(f[i][j], f[i - 1][((j - a[i]) % 3 + 3) % 3] + 1);
if (f[i][j] == f[i - 1][((j - a[i]) % 3 + 3) % 3] + 1)
p[i][j] = 1;
if (f[i][j] == f[i - 1][j])
p[i][j] = 0;
}
}
if (f[n][0] < 0)
{
for (int i = 1; i <= n; i++)
if (a[i] == 0)
{
cout << 0 << endl;
return 0;
}
cout << -1 << endl;
return 0;
}
int pos = 0;
vector<int> ans;
for (int i = n; i >= 1; i--)
{
if (p[i][pos] == -1)
{
ans.push_back(a[i]);
break;
}
else if (p[i][pos] == 1)
{
ans.push_back(a[i]);
pos = (pos - a[i] % 3 + 3) % 3;
}
}
if (ans.size())
for (int i = ans.size() - 1; i >= 0; i--)
cout << ans[i];
}