[CF792C] Divide by Three(dp,记录路径)

题目链接:http://codeforces.com/contest/792/problem/C

题意:给个超长整数,问最少删掉几个数,使得这个数能被3整除。输出这个删掉字符后的字符串。

当然这个数各位加起来能被三整除,那么这个数就能被三整除。

很容易的dp,f(i,j)表示前i个字符各位和%3=j时,最少删掉几个字符。每层初始化为f(i,j) = min(f(i,j), f(i-1,j)+1)

转移就很简单,当前数为x,那么当前可以由f(i-1,(j-x+3)%3)转移过来。

有几个坑需要注意下:

1.初始化,要特别小心前导零存在的时候(s[0]-'0')%3==0的情况,因此判断一下是更新两个初始值还是一个就行。

2.再就是前导零处理起来特别麻烦,太麻烦了,参考了mengxiang巨的前导零排除方法,用每层初始化的值(删除)和当前字符个数判断,假如全删了,那说明当前状态之前都是0,后面就不转移了。

3.假如删了n个字符,要处理一下这个字符串是不是原本就有0,因为排除前导零的时候没有转移。

  1 /*
  2 ━━━━━┒ギリギリ♂ eye!
  3 ┓┏┓┏┓┃キリキリ♂ mind!
  4 ┛┗┛┗┛┃\○/
  5 ┓┏┓┏┓┃ /
  6 ┛┗┛┗┛┃ノ)
  7 ┓┏┓┏┓┃
  8 ┛┗┛┗┛┃
  9 ┓┏┓┏┓┃
 10 ┛┗┛┗┛┃
 11 ┓┏┓┏┓┃
 12 ┛┗┛┗┛┃
 13 ┓┏┓┏┓┃
 14 ┃┃┃┃┃┃
 15 ┻┻┻┻┻┻
 16 */
 17 #include <bits/stdc++.h>
 18 using namespace std;
 19 #define fr first
 20 #define sc second
 21 #define cl clear
 22 #define BUG puts("here!!!")
 23 #define W(a) while(a--)
 24 #define pb(a) push_back(a)
 25 #define Rint(a) scanf("%d", &a)
 26 #define Rll(a) scanf("%I64d", &a)
 27 #define Rs(a) scanf("%s", a)
 28 #define Cin(a) cin >> a
 29 #define FRead() freopen("in", "r", stdin)
 30 #define FWrite() freopen("out", "w", stdout)
 31 #define Rep(i, len) for(int i = 0; i < (len); i++)
 32 #define For(i, a, len) for(int i = (a); i < (len); i++)
 33 #define Cls(a) memset((a), 0, sizeof(a))
 34 #define Clr(a, x) memset((a), (x), sizeof(a))
 35 #define Full(a) memset((a), 0x7f7f7f, sizeof(a))
 36 #define lrt rt << 1
 37 #define rrt rt << 1 | 1
 38 #define pi 3.14159265359
 39 #define RT return
 40 #define lowbit(x) x & (-x)
 41 #define onenum(x) __builtin_popcount(x)
 42 typedef long long LL;
 43 typedef long double LD;
 44 typedef unsigned long long ULL;
 45 typedef pair<int, int> pii;
 46 typedef pair<string, int> psi;
 47 typedef pair<LL, LL> pll;
 48 typedef map<string, int> msi;
 49 typedef vector<int> vi;
 50 typedef vector<LL> vl;
 51 typedef vector<vl> vvl;
 52 typedef vector<bool> vb;
 53 
 54 const int maxn = 101010;
 55 const int inf = 0x7f7f7f7f;
 56 int n, f[maxn][3], path[maxn][3];
 57 char s[maxn];
 58 
 59 signed main() {
 60     // FRead();
 61     while(~Rs(s)) {
 62         n = strlen(s);
 63         if(n == 1) {
 64             if((s[0]-'0')%3==0) puts(s);
 65             else puts("-1");
 66             continue;
 67         }
 68         Clr(f, 0x7f); Clr(path, -1);
 69         if((s[0]-'0')%3==0) f[0][0] = 0;
 70         else f[0][0] = 1, f[0][(s[0]-'0')%3] = 0;
 71         For(i, 1, n) {
 72             int x = (s[i] - '0') % 3;
 73             Rep(j, 3) {    // delete
 74                 if(f[i][j] > f[i-1][j] + 1) {
 75                     f[i][j] = f[i-1][j] + 1;
 76                     path[i][j] = j;
 77                 }
 78             }
 79             Rep(j, 3) {
 80                 if(x == 0) {
 81                     if(s[i] == '0') {
 82                         if(f[i-1][j] == i) {
 83                             continue; // 0
 84                         }
 85                     }
 86                 }
 87                 int pre = (j - x + 3) % 3;
 88                 if(f[i][j] > f[i-1][pre]) {
 89                     f[i][j] = f[i-1][pre];
 90                     path[i][j] = pre;
 91                 }
 92             }
 93         }
 94         // cout << f[n-1][0] << endl;
 95         if(f[n-1][0] == n) {
 96             bool ok = 0;
 97             Rep(i, n) if(s[i] == '0') ok = 1;
 98             if(ok) puts("0");
 99             else puts("-1");
100             continue;
101         }
102         int i = n - 1, j = 0, pre;
103         string ret = "";
104         while(i) {
105             pre = path[i][j];
106             if(f[i-1][pre] == f[i][j]) ret += s[i];
107             j = pre; i--;
108         }
109         if((s[i] - '0') % 3 == pre) ret += s[i];
110         reverse(ret.begin(), ret.end());
111         cout << ret << endl;
112     }
113     RT 0;
114 }
原文地址:https://www.cnblogs.com/kirai/p/7388853.html