Path to Integer_ABC402分析与解答
考虑怎么降低复杂度,使用分治策略降低搜索的复杂度。
对于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;
}