Kirinriki
题目链接:Kirinriki
题意:找两个不重叠的子串A,B。 使得 dis(A,B)<=m;
dis(A,B)=∑n−1i=0|Ai−Bn−1−i| 。求最长的字符串长度。
思路:
直接枚举终点,由于奇偶位的不同,所以我们需要枚举奇和偶两种情况
官方题解:
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e3+5;
char str[maxn];
int m,ans,len;
void solve(int ed1,int ed2)
{
int st1=ed1,st2=ed2,tot=0;
if(ed1<0)
return ;
while(st1>=0&&st2<len)
{
if(tot+abs(str[st1]-str[st2])<=m)
{
tot+=abs(str[st1]-str[st2]);
ans=max(ans,ed1-st1+1);
--st1,++st2;
}
else
{
tot-=abs(str[ed1]-str[ed2]);
--ed1,++ed2;
}
}
}
int main()
{
int T_T;
scanf("%d",&T_T);
while(T_T--)
{
scanf("%d %s",&m,str);
len=strlen(str);
ans=0;
for(int i=0;i<len-1;++i)
{
solve(i,i+1);
solve(i-1,i+1);
}
printf("%d\n",ans);
}
return 0;
}
ps:我在比赛过程中写的是枚举起点,分为
st1=0,st2=[1,len-1]
st1=len-1,st2=[0,len-2]两种情况
当时吧,认为这样写肯定是对的,于是想都没想清楚就交了,结果wrong了无数发。。。(思路真的是对的,是我的过程有一点错误-_-)
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e3+5;
char str[maxn];
int m;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&m);
scanf("%s",str);
int len=strlen(str),ans=0;
for(int l=1;l<len;++l)
{
int st1=0,st2=st1+l;
int tot=abs(str[st1]-str[st2]);
while(tot>m)
{
++st1,--st2;//这里写成了++st1,++st2 ︸_︸
if(st1>=st2)
break;
tot=abs(str[st1]-str[st2]);
}
if(st1>=st2)
continue;
int ed1=st1,ed2=st2;
while(1)
{
while(tot<=m)
{
ans=max(ans,ed1-st1+1);
++ed1,--ed2;
if(ed1>=ed2)
break;
tot+=abs(str[ed1]-str[ed2]);
}
if(ed1>=ed2)
break;
while(tot>m)
{
tot-=abs(str[st1]-str[st2]);
++st1,--st2;
if(st1>ed1||st2<ed2)
break;
}
if(st1>ed1||st2<ed2)
break;
}
}
for(int l=1;l<len;++l)
{
int st1=len-1,st2=st1-l;
int tot=abs(str[st1]-str[st2]);
while(tot>m)
{
--st1,++st2;//这里写成了--st1,--st2 T_T
if(st1<=st2)
break;
tot=abs(str[st1]-str[st2]);
}
if(st1<=st2)
continue;
int ed1=st1,ed2=st2;
while(1)
{
while(tot<=m)
{
ans=max(ans,ed2-st2+1);
--ed1,++ed2;
if(ed2>=ed1)
break;
tot+=abs(str[ed1]-str[ed2]);
}
if(ed2>=ed1)
break;
while(tot>m)
{
tot-=abs(str[st1]-str[st2]);
--st1,++st2;
if(st1<ed1||st2>ed2)
break;
}
if(st1<ed1||st2>ed2)
break;
}
}
printf("%d\n",ans);
}
return 0;
}