考虑怎么降低复杂度,使用分治策略降低搜索的复杂度。
对于a_i,j,其一定在最后结果数的第(2n-i-j)位(如果将最低位看成第0位),故将a_i,j看成a_i,j * 10^(2n-i-j),这样每次加上a_i,j就可以了。
从(1,1)到(n,n)一定会经过右上-左下这条对角线上的点,这些点分别是(1,n),(2,n-1)....(n,1),从(1,1)走到这些点走的步数是n-1,从这些点走到(n,n)走的步数也是n-1,并且对于一个固定的对角线上的点p,从(1,1)走到p要走的横向步数和纵向步数是确定的,从p走到(n,n)要走的横向步数和纵向步数也是确定的,记录从(1,1)到p走出的所有结果,从小到大排序并去重,得到数组s1,同样记录从p到(n,n)走出的所有结果,从小到大排序并去重,得到数组s2,对s1中的每一个元素x,如果s2中的元素y使得x+y>=m,则这样的y不如使得x+y<m的y,在使得x+y<m的y中,我们选最大的y,如果没有使得x+y<m的y,就选x+y>=m的y中最大的
复杂度上限估计:NlogN
#include<bits/stdc++.h>
using namespace std;
using ll=long long ;
const ll N=40,maxn=25;
ll n,m,cnt1,cnt2;
ll md[maxn<<1],a[maxn][maxn];
vector<ll> s1,s2;
void dfs(ll x,ll y,ll xrem,ll yrem,ll sum,ll t){
if(xrem==0 && yrem==0) {
if(t==1) s1.push_back(sum);
if(t==2) s2.push_back(sum);
return;
}
if(xrem>0) dfs(x+1,y,xrem-1,yrem,(sum+a[x+1][y])%m,t);
if(yrem>0) dfs(x,y+1,xrem,yrem-1,(sum+a[x][y+1])%m,t);
}
ll bin_search(ll top){
ll ans=-1;
ll l=0,r=cnt2;
while(l<r) {
ll mid=(l+r)>>1;
if(s2[mid]<=top) {
ans=s2[mid];
l=mid+1;
}else {
r=mid;
}
}
if(ans==-1) ans=s2[cnt2-1];
return ans;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin>>n>>m;
md[0]=1%m;
for(ll i=1;i<=N;i++) md[i]=md[i-1]*10%m;
for(ll i=1;i<=n;i++){
for(ll j=1;j<=n;j++){
cin>>a[i][j];
a[i][j]=a[i][j]%m*md[2*n-i-j]%m;
}
}
ll ans=0;
for(ll i=1;i<=n;i++){
s1.clear();s2.clear();
dfs(1,1,i-1,n-i,a[1][1],1);
dfs(i,n-i+1,n-i,i-1,0,2);
stable_sort(s1.begin(),s1.end());
cnt1=unique(s1.begin(),s1.end())-s1.begin();
stable_sort(s2.begin(),s2.end());
cnt2=unique(s2.begin(),s2.end())-s2.begin();
for(ll j=0;j<cnt1;j++){
ll x=s1[j];
ll top=m-1-x;
ll y=bin_search(top);
ans=max(ans,(x+y)%m);
}
}
cout<<ans<<"\n";
return 0;
}
172万+

被折叠的 条评论
为什么被折叠?



