题意
有一个
n∗m
的矩阵
A
,每个格子有一个权值。要你找一条从
输入两个数组
U
和
n,m<=10000
,要求输出路径。空间限制
5120KB
。
分析
一开始还以为解题的关键在权值上,后来想了想觉得这样设权值只是为了随机,真正要考虑的是如何在优先的空间内输出路径。
我们设
solve(lr,rr,lc,rc)
表示输出从
(lr,lc)
走到
(rr,rc)
的路径。
设
mid=(lr+rr)/2
,那么从从
(lr,lc)
走到
(rr,rc)
的路径一定会有一步是从第
mid
行走到第
mid+1
行。
我们可以通过dp一次来确定那一步的纵坐标,设为
p
,然后分治
当
lr=rr
时,就只能不停的向右走,然后直接退出就好了。
不难发现在dp的过程中我们只需要
O(n)
大小的数组,所以空间复杂度是
O(n)
。
考虑一下这样做的时间复杂度:
设
i=rr−lr+1,j=rc−lc+1
,dp一次的复杂度是
O(ij)
。
那么有
T(i,j)=ij+T(i2,k)+T(i2,j−k)
不难发现有
i2∗k+i2∗(j−k)=ij2
,所以总的复杂度是
nm+nm2+nm4...
也就是
O(nm)
。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int N=10005;
const LL inf=(LL)1e18;
int n,m,a[N],b[N],now,from[N];
LL f[N];
bool ans[N*2],pre[N];
queue<int> que;
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void dp(LL *f,int l,int r)
{
for (int i=l;i<=r;i++)
for (int j=1;j<=m;j++)
f[j]=min(f[j],f[j-1])+((a[i]+j)^(b[j]+i));
}
void solve(int lr,int rr,int lc,int rc)
{
if (lr==rr)
{
for (int i=lc;i<rc;i++) ans[now--]=0;
return;
}
int mid=(lr+rr)/2;
for (int i=lc-1;i<=rc;i++) f[i]=inf,from[i]=i;f[lc]=0;
for (int i=lr;i<=mid;i++)
for (int j=lc;j<=rc;j++)
f[j]=min(f[j],f[j-1])+((a[i]+j)^(b[j]+i));
for (int i=mid+1;i<=rr;i++)
for (int j=lc;j<=rc;j++)
{
from[j]=f[j]<f[j-1]?from[j]:from[j-1];
f[j]=min(f[j],f[j-1])+((a[i]+j)^(b[j]+i));
}
int p=from[rc];
solve(mid+1,rr,p,rc);
ans[now--]=1;
solve(lr,mid,lc,p);
}
int main()
{
n=read();m=read();
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<=m;i++) b[i]=read();
now=n+m-2;
solve(1,n,1,m);
for (int i=1;i<=n+m-2;i++) putchar(ans[i]?'D':'R');
return 0;
}