题意:给一串上下左右的字符串和一个坐标,定义修改操作是修改某个子串,费用为该子串长度,求最少花费多少能从原点到达目标点
打的时候总是觉得要枚举起点和终点,或者起点和长度,所以n方是避免不了的。
赛后看题解发现,我们只关心长度,并不关心起点和中间具体是怎样修改的,所以可以二分长度。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5 + 100;
int L[N],U[N],R[N],D[N];
int n,x,y;
bool Che(int len)
{
int nowx=0,nowy=0,dis;
for(int i=0;i<=n-len;i++)///枚举起点
{
if(i==0)
{
if(len)
{
nowx=R[n-1]-R[i+len-1]-(L[n-1]-L[i+len-1]);
nowy=U[n-1]-U[i+len-1]-(D[n-1]-D[i+len-1]);
}
else
{
nowx=R[n-1]-L[n-1];
nowy=U[n-1]-D[n-1];
}
}
else
{
nowx=R[i-1]-L[i-1]+R[n-1]-R[i+len-1]-(L[n-1]-L[i+len-1]);
nowy=U[i-1]-D[i-1]+U[n-1]-U[i+len-1]-(D[n-1]-D[i+len-1]);
}
dis=abs(nowx-x)+abs(nowy-y);
if(dis<=len)return 1;
}
return 0;
}
int main()
{
string s;
while(cin>>n)
{
cin>>s;
cin>>x>>y;
int dd=abs(x)+abs(y);
if(dd>n||abs(dd-n)%2)
{
printf("-1\n");
continue;
}
L[0]=s[0]=='L';
R[0]=s[0]=='R';
U[0]=s[0]=='U';
D[0]=s[0]=='D';
for(int i=1;i<n;i++)
{
L[i]=L[i-1]+(s[i]=='L');
R[i]=R[i-1]+(s[i]=='R');
D[i]=D[i-1]+(s[i]=='D');
U[i]=U[i-1]+(s[i]=='U');
}
int l=0,r=n,mid;
while(r-l>1)
{
mid=(l+r)>>1;
if(Che(mid))r=mid;
else l=mid;
}
if(Che(l))
printf("%d\n",l);
else if(Che(r))
printf("%d\n",r);
else
printf("???\n");
}
return 0;
}