Codeforces - 41 D. Pawn(dp[刷表] + 路径输出)

Pawn

On some square in the lowest row of a chessboard a stands a pawn. It has only two variants of moving: upwards and leftwards or upwards and rightwards. The pawn can choose from which square of the lowest row it can start its journey. On each square lay from 0 to 9 peas. The pawn wants to reach the uppermost row having collected as many peas as possible. As there it will have to divide the peas between itself and its k brothers, the number of peas must be divisible by k + 1. Find the maximal number of peas it will be able to collect and which moves it should make to do it.

The pawn cannot throw peas away or leave the board. When a pawn appears in some square of the board (including the first and last square of the way), it necessarily takes all the peas.

Input

The first line contains three integers nmk (2 ≤ n, m ≤ 100, 0 ≤ k ≤ 10) — the number of rows and columns on the chessboard, the number of the pawn's brothers. Then follow n lines containing each m numbers from 0 to 9 without spaces — the chessboard's description. Each square is described by one number — the number of peas in it. The first line corresponds to the uppermost row and the last line — to the lowest row.

Output

If it is impossible to reach the highest row having collected the number of peas divisible by k + 1, print -1.

Otherwise, the first line must contain a single number — the maximal number of peas the pawn can collect given that the number must be divisible by k + 1. The second line must contain a single number — the number of the square's column in the lowest row, from which the pawn must start its journey. The columns are numbered from the left to the right with integral numbers starting from 1. The third line must contain a line consisting of n - 1 symbols — the description of the pawn's moves. If the pawn must move upwards and leftwards, print L, if it must move upwards and rightwards, print R. If there are several solutions to that problem, print any of them.

Examples

input

3 3 1
123
456
789

output

16
2
RL

input

3 3 0
123
456
789

output

17
3
LR

input

2 2 10
98
75

output

-1

题意:给一个矩阵,每个值都是 0 ~ 9,一个士兵从最后一行的某个位置出发,在格子 (i,j) 能够获得 (i,j) 位置的矩阵值,每一次只能往左上或者右上移动,问最后移动到第一行时的能够获得的  最大且是 s + 1 的整数倍的值是多少,并打印路径

思路:是 s + 1 的整数倍,考虑到 s 的范围不超过10,于是有 dp[i][j][k] 表示在 i , j 位置 mod s == k 的最大值。

设当前位置为 (i, j),矩阵为 A ,x = A[i - 1][j - 1],y = A[i - 1][j + 1] ,S = s + 1。那么有状态转移方程

dp[i-1][j - 1][(k + x) \%S]=max(dp[i-1][j - 1][(k + x) \%S],\ \ dp[i][j][k]+x)

dp[i-1][j + 1][(k + y) \%S]=max(dp[i-1][j + 1][(k + y) \%S],\ \ dp[i][j][k]+y)

对于路径输出,就多开两个数组 pathj 和 paths,分别表示[i][j][k] 时的 j 和 k 是多少,具体可看代码

Code:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define fi first
#define se second
#define CLR(a) while(!(a).empty()) a.pop()

using namespace std;
inline LL read() {
    LL s = 0,w = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') w = -1;
        ch = getchar();
    }
    while(isdigit(ch))
        s = s * 10 + ch - '0',ch = getchar();
    return s * w;
}
inline void write(LL x) {
    if(x < 0)
        putchar('-'), x = -x;
    if(x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

const int maxn = 110;
int a[maxn][maxn];
int dp[maxn][maxn][20];
int pathj[maxn][maxn][20];
int paths[maxn][maxn][20];

int main() {
//#ifndef ONLINE_JUDGE
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
    int n = read(),m = read(),s = read();
    for(int i = 1;i <= n;++ i)
        for(int j = 1;j <= m;++ j){
            char ch; scanf(" %c",&ch);
            a[i][j] = ch - '0';
        }
    ++ s;
    clr(dp,-0x3f);
    for(int j = 1;j <= m;++ j){
        dp[n][j][a[n][j] % s] = a[n][j];
        pathj[n][j][a[n][j] % s] = j;
        paths[n][j][a[n][j] % s] = a[n][j];
    }
    for(int i = n;i > 1;-- i)
        for(int j = 1;j <= m;++ j)
            for(int k = 0;k < s;++ k){
                int x;
                if(j != 1){
                    x = a[i - 1][j - 1];
                    if(dp[i - 1][j - 1][(k + x) % s] < dp[i][j][k] + x){
                        dp[i - 1][j - 1][(k + x) % s] = dp[i][j][k] + x;
                        pathj[i - 1][j - 1][(k + x) % s] = j;
                        paths[i - 1][j - 1][(k + x) % s] = k;
                    }
                }
                if(j != m){
                    x = a[i - 1][j + 1];
                    if(dp[i - 1][j + 1][(k + x) % s] < dp[i][j][k] + x){
                        dp[i - 1][j + 1][(k + x) % s] = dp[i][j][k] + x;
                        pathj[i - 1][j + 1][(k + x) % s] = j;
                        paths[i - 1][j + 1][(k + x) % s] = k;
                    }
                }
            }
    int ans = -1,id;
    for(int j = 1;j <= m;++ j){
//        debug(dp[1][j][0]);
        if(ans < dp[1][j][0]) ans = dp[1][j][0], id = j;
    }
    if(ans == -1){ write(ans); return 0; }
    write(ans); putchar('\n');
    int i = 1,k = 0;
    string ppath = "";
    while(i < n){
        if(pathj[i][id][k] > id)
            ppath += 'L';
        else ppath += 'R';
        int tmp = id;
        id = pathj[i][tmp][k];
        k = paths[i][tmp][k];
        ++ i;
    }
    write(id);  putchar('\n');
    for(int i = ppath.size() - 1;i >= 0;-- i) putchar(ppath[i]);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值