题目链接:http://codeforces.com/contest/792/problem/C
题意:给了一个字符串,问能否删除一些数字使得这个数能被3整除,输出任意一个删除次数最小的剩下的数字串的合法解。
解法:Dp。dp[l]][zero][mod]代表第l位,是否有前导0,对3取模的最少删除次数
可以发现状态数最多100000*2*3,所以大力记忆化搜索,还要在搜索的过程中记录一下那些是被删除了。还有个坑了的地方就是特判0。

//CF 792C

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100005;
int dp[maxn][2][3]; ///dp[i][j][k]代表第i位,是否有前导0,对3取模的最少删除次数
int path[maxn][2][3]; ///记录路径
int n, cnt, ans[maxn];
string s;

int dfs(int l, int zero, int mod)
{
    if(~dp[l][zero][mod]) return dp[l][zero][mod];
    if(l == n){
        if(zero&&!mod) return 0;
        else return -inf;
    }
    int x, y = -inf;
    x = dfs(l+1, zero, mod);
    path[l][zero][mod] = 0;
    if(s[l] != '0' || (s[l] == '0' && zero)){
        y = dfs(l+1, 1, (mod+(s[l]-'0')%3)%3) + 1;
        if(y > x){
            path[l][zero][mod] = 1;
            return dp[l][zero][mod] = y;
        }
    }
    return dp[l][zero][mod] = x;
}

void print_path(int l, int zero, int mod)
{
    if(l == n) return;
    if(path[l][zero][mod]){
        ans[cnt++] = l;
        print_path(l+1, 1, (mod+(s[l]-'0')%3)%3);
    }else{
        print_path(l+1, zero, mod);
    }
}

int main()
{
    cin >> s;
    n = s.size();
    memset(dp, -1, sizeof(dp));
    int answer = dfs(0, false, 0);
    if(answer <= 0){
        bool flag = 0;
        for(int i = 0; i < n; i++){
            if(s[i] == '0'){
                flag = 1;
                break;
            }
        }
        if(flag){
            puts("0");
        }
        else{
            puts("-1");
        }
    }
    else{
        cnt = 0;
        memset(ans, 0, sizeof(ans));
        print_path(0, false, 0);
        for(int i = 0; i < cnt; i++){
            putchar(s[ans[i]]);
        }
        printf("\n");
    }
    return 0;
}