Loading

cf41d

CF41D Pawn

link

题意

给定一个矩阵,从底走到顶,每次可以向左上或右上移动,求路径上数字和最大且使 \(M\) 可整除,无解输出 -1\(1\leq n,m\leq 100,a_{i,j}\in [0,9]\)

题解

如果没有模 \(k+1\) 的限制的话就是个朴素的二维 dp。有了限制考虑加上一维 \(k\) 表示和模 \(M\) 等于 \(k\)。所以 \(f_{i,j,k}=\max(f_{i,j,k},f_{i+1,j-1,p}+a_{i,j},f_{i+1,j+1,p}+a_{i,j})\),其中 \(p\) 是和去掉 \(a_{i,j}\) 的余数。还要求输出方案数,倒着推回去就行。复杂度 \(O(nmk)\)aclink

  • 注意 \(p=(k-a_{i,j}\bmod M+M)\bmod M\),以防止有负数。
  • 注意特判超出边界的各种情况。

代码

#include<bits/stdc++.h>
#define i64 long long
#define L(a,b,c,d) for(int a=b;a<=c;a+=d)
#define R(a,b,c,d) for(int a=b;a>=c;a-=d)

using namespace std;
const int N=105;

void solve();
int n,m,M,a[N][N],f[N][N][N];

signed main(){
  int Test=1;
//  scanf("%d",&Test);
  while(Test--) solve();
  return 0;
}

void solve(){
  scanf("%d%d%d",&n,&m,&M);
  M+=1;
  L(i,1,n,1){
    char s[N];
    scanf("%s",s+1);
    L(j,1,m,1) a[i][j]=s[j]-'0';
  }
  memset(f,255,sizeof f);
  L(j,1,m,1) f[n][j][a[n][j]%M]=a[n][j];
  R(i,n-1,1,1){
    L(j,1,m,1){
      L(k,0,M-1,1){
        int p=(((k-a[i][j])%M)+M)%M;
        if(j>1&&f[i+1][j-1][p]!=-1) f[i][j][k]=max(f[i][j][k],f[i+1][j-1][p]+a[i][j]);
        if(j<m&&f[i+1][j+1][p]!=-1) f[i][j][k]=max(f[i][j][k],f[i+1][j+1][p]+a[i][j]);
      }
    }
  }
  int x=0;
  L(j,1,m,1){
    if(f[1][j][0]>f[1][x][0]) x=j;
  }
  if(f[1][x][0]<0){
    printf("-1\n");
    return;
  }
  printf("%d\n",f[1][x][0]);
  int k=0,p=0,j=x;
  vector<char> ans;
  L(i,1,n-1,1){
    p=(((k-a[i][j])%M)+M)%M;
    if(j==1) ans.push_back('L'),j++;
    else if(j==m) ans.push_back('R'),j--;
    else if(f[i][j][k]==f[i+1][j-1][p]+a[i][j]) ans.push_back('R'),j--;
    else ans.push_back('L'),j++;
    k=p;
  }
  printf("%d\n",j);
  reverse(ans.begin(),ans.end());
  for(char c:ans) printf("%c",c);
}
posted @ 2025-10-05 18:19  jess1ca1o0g3  阅读(5)  评论(0)    收藏  举报