Atcoder ABC 402

· · 题解

#include<bits/stdc++.h>
using namespace std;
int n,m,a[25][25],pw[50];
vector<int>g1[25],g2[25];
int main(){
    scanf("%d%d",&n,&m);
    //1.预处理a 乘上权值
    pw[0]=1;
    for(int i=1;i<=n*2-2;i++)
        pw[i]=(pw[i-1]*10ll)%m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            scanf("%d",&a[i][j]);
            a[i][j]=(1ll*a[i][j]*pw[n*2-i-j])%m;
        }
    //2.从(1,1)出发走一半路程到(x,n-x+1) 即n-1步 用二进制枚举过程 1向下 0向右
    for(int i=0;i<(1<<(n-1));i++){
        int x=1,y=1,res=a[1][1];
        for(int j=0;j<n-1&&x<=n&&y<=n;j++){
            if((i>>j)&1) x++;
            else y++;
            res=(res+a[x][y])%m;//先走后加
        }
        if(x<=n&y<=n) g1[x].push_back(res);//将有效答案存入g1
    }
    //3.从(n,n)出发走一半路程到(x,n-x+1) 即n-1步 用二进制枚举过程 1向上 0向左
    for(int i=0;i<(1<<(n-1));i++){
        int x=n,y=n,res=0;
        for(int j=0;j<n-1&&x>=1&&y>=1;j++){
            res=(res+a[x][y])%m;//避免重复计算(x,n-x+1)的点 先加后走
            if((i>>j)&1) x--;
            else y--;
        }
        if(x>=1&&y>=1) g2[x].push_back(res);//存入g2
    }
    //4.贪心匹配两组答案
    int ans=0;
    for(int i=1;i<=n;i++){//考虑每个相交的点
        sort(g1[i].begin(),g1[i].end());//将所有答案排序
        sort(g2[i].begin(),g2[i].end());
        for(int x=g1[i].size()-1,y=0;x>=0;x--){//固定g1 找到最大的g2
            while(y<g2[i].size()&&g1[i][x]+g2[i][y]<m) y++;//不取模下的最大值
            if(y) ans=max(ans,g1[i][x]+g2[i][y-1]);//判断数组越界
            ans=max(ans,(g1[i][x]+g2[i].back())%m);//取模一定取最大值
        }
    }
    printf("%d",ans);
    return 0;
}//第三