C. Divide by Three DP

时间:2024-10-03 17:36:02

http://codeforces.com/contest/792/problem/C

这题奇葩题我居然用dp过了。

如果要模拟的话,可以用一个栈保存,保存每一个%3 = 2的pos,%3 = 1的pos,注意到题目是最多删除2个数,就能使得整个数%3=0了,如果要删除前导0的话就另外算。

那么贪心从栈顶删除,也就是先删除后面的数就行。然后需要删除2,又分两种情况,删除两个1和删除一个2。。等等,一路模拟。

比赛的时候没想到这样,也觉得很复杂,于是就dp了,虽然TLE了,但是加了一个剪枝就过了,dfs很玄

我用dp[i][j]表示,前i位中,模3后余数是j的最大合法长度,最大合法长度,也就是不能含有前导0.所以1001这样的情况求出来是无解的,需要特判一下。

那么求到了这个长度之后

题目就变成了,给出n个数字,选出k个,使得组合起来得数字%3 = 0,不能含有前导0.

我想不到好的算法,就dfs暴力了。感觉应该会超时,但是剪了剪支居然46ms

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 1e5 + ;
char str[maxn];
int dp[maxn][], lenstr; //dp出答案
vector<char>ans;
bool dfs(int cur, int now, int len, int pre) {
if (now == && len == dp[lenstr][]) return true;
if (cur == lenstr + ) return false;
if (len >= dp[lenstr][]) return false;
if (lenstr - cur + + len < dp[lenstr][]) return false;
if (str[cur] == '') {
if (pre) {
if (dfs(cur + , now, len + , )) {
ans.push_back(str[cur]);
return true;
}
return dfs(cur + , now, len, pre);
} else {
return dfs(cur + , now, len, pre);
}
} else {
if (dfs(cur + , (now + str[cur] - '') % , len + , )) {
ans.push_back(str[cur]);
return true;
}
return dfs(cur + , now, len, pre);
}
}
void work() {
scanf("%s", str + );
lenstr = strlen(str + );
memset(dp, -0x3f, sizeof dp);
dp[][] = ;
int flag = inf;
for (int i = ; i <= lenstr; ++i) {
if ((str[i] - '') % == ) flag = i;
for (int j = ; j < && i > ; ++j) {
dp[i][j] = dp[i - ][j];
}
//不是0的,自己作为一个
if (str[i] != '') dp[i][(str[i] - '') % ] = max(dp[i][(str[i] - '') % ], );
for (int j = ; j < ; ++j) {
int res = (j * + str[i] - '') % ;
dp[i][res] = max(dp[i][res], dp[i - ][j] + );
}
}
// cout << dp[lenstr][0] << endl;
if (dp[lenstr][] < && flag == inf) {
cout << - << endl;
return;
}
if (dp[lenstr][] < && flag != inf) {
cout << str[flag];
return;
}
dfs(, , , );
reverse(ans.begin(), ans.end());
for (int i = ; i < ans.size(); ++i) {
cout << ans[i];
}
}
int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}