[ARC119F] AtCoder Express 3
观察样例 1 的解释,发现切换类型的方法是比较单一的
这种就是直接走一段换一段,我们可以人为钦定换乘时最多走一步,因为相邻的同色也可以视作走车站
这种情况复杂一些,需要往回走一段,但是依然可以发现往回走也至多一步,因为如果走了两步说明往回走了一步到达的车站依然同色,那么走的车站必然不会是后面那一个
根据这两个性质,发现最短路的形态非常单一,只会从上一个红色或蓝色的车站转移过来,因此设 \(dp_{i,j,k,0/1}\) 表示考虑到第 \(i\) 个车站,上一个红色的车站的最短路为 \(j\),蓝色的为 \(k\),上一个车站为红 \(/\) 蓝色,转移时考虑如果上一步放红色车站,且这一步放红色车站,那么红色车站最短路更新为 \(j+1\),蓝色无法更新,如果放蓝色车站,那么红色车站最短路更新为 \(min(j,k+2)\),蓝色车站最短路更新为 \(min(j+1,k+1)\),上一步放红色车站是对称的
这样做的复杂度是 \(O(n^3)\),发现最短路更新时,仅当 \(|j-k|<2\) 时才可能无法确定最短路的更新,否则与 \(|j-k|=2\) 的情况是等价的,因此复杂度优化到 \(O(n^2)\)
点击查看代码
#include<bits/stdc++.h>
#define N 4005
using namespace std;
int read(){
int w=0,h=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')h=-h;ch=getchar();}
while(ch>='0'&&ch<='9'){w=w*10+ch-'0';ch=getchar();}
return w*h;
}
const int mod=1e9+7;
int n,m,ans,dp[N][N][6][2];char S[N];
int&DP(int i,int x,int y,int t){x=min(x,y+2);y=min(y,x+2);return dp[i][x][y-x+2][t];}
void add(int&x,int y){(x+=y)>=mod?x-=mod:x;}
signed main(){
n=read();m=read();scanf("%s",S+1);
dp[0][0][2][0]=1;
for(int i=1;i<n;i++)
for(int j=0;j<=i;j++)
for(int k=j-2;k<=j+2;k++){
if(S[i]=='A'||S[i]=='?'){
add(DP(i,j+1,k,0),DP(i-1,j,k,0));
add(DP(i,min(j+1,k+1),min(j+2,k),0),DP(i-1,j,k,1));
}
if(S[i]=='B'||S[i]=='?'){
add(DP(i,j,k+1,1),DP(i-1,j,k,1));
add(DP(i,min(j,k+2),min(j+1,k+1),1),DP(i-1,j,k,0));
}
}
for(int i=0;i<=n;i++)
for(int j=i-2;j<=i+2;j++)
if(min(i,j)<m)add(ans,(DP(n-1,i,j,0)+DP(n-1,i,j,1))%mod);
printf("%d\n",ans);
return 0;
}