arc119f
arc119f
题意:有\(n+1\)个按编号顺次的站台,其中\(0\)和\(n\)站台既能坐\(A\)号列车也能坐\(B\)号列车,除\(0\)和\(n\)站台外,其他站台为\(A\)或\(B\)或未知
乘坐\(AB\)列车花费1能到达下一个或上一个有此号车的站台,除此之外还可以花费1到相邻的站台
现给出每个站台(可能)有的列车,求从0到n花费最小值不超过K的方案数
\(2\leq n\leq 4000\).答案取模\(10^9+7\)
首先我们不难得出\(O(2^nn)\)的暴力,但是这跟正解没什么关系,这里就不讲了
我们从第一个站台从前往后\(dp\),由于影响一个状态能否胜利的因素只有到达最右边的\(A\)的最短路和到达最右边的\(B\)的最短路,所以我们可以设计状态\(f_{x,y,z}\)表示当前dp到第\(x\)个站台,到前\(x\)个站台中最右边\(A\)的最短路为\(x\),到前\(x\)个站台中最右边\(B\)的最短路为\(y\)的方案数(0和n+1视为AB均可)
这样的时空复杂度为\(O(n^3)\),不能通过
我们考虑下\(y,z\)是否有关系
很显然,没有任何关系,比如\(ABBBB...B\)就能让\(y,z\)差上很多
此时我们就将状态改变一下:\(f_{x,y,z}\)表示当前dp到第\(x\)个站台,到前\(x\)个站台中最右边\(A\)或它右边A的最短路为\(y\),到前\(x\)个站台中最右边\(B\)或它右边B的最短路为$$的方案数z
为什么可以这样设计呢?
原因在于我们不需要知道它是否能在\(y(z)\)步内到达某个\(A(B)\)站台,我们只关心它能否能在m步内到达终点n+1,所以设计状态时不必在某步刚好走到某个站台,只需其走到某个站台右边的站台即可
这样\(y,z\)有限制吗?
这样不会超过2.
为什么呢?
假设存在(最右)A在(最右)B左边,A比B最短距离长3,则A只需往右走到下一个A,再往左走一步,则走到了一个B,显然它在站台\(x\)右边,矛盾
因此,\(y,z\)的差值不会超过\(2\)
此时时空复杂度为\(O(n^2)\),可能可以通过数据结构优化 (但我不会)
#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
T t=0;
char k;
bool vis=0;
do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
# define mod 1000000007
int s,m,h[4005][5][2],t[4005][5][2],(*f)[5][2],(*g)[5][2];//left is (0:A 1:B)
char str[4005];
# define Up(x,y) (((x)+=(y))%=mod)
int main(){
s=read-1;m=read;f=h+1;g=t+1;
scanf("%s",str+1);
if(str[1]!='A')f[0][1][0]=1;
if(str[1]!='B')f[0][1][1]=1;
for(int i=2;i<=s;++i){
for(int j=0;j<=i;++j)memset(t[j],0,sizeof(t[j]));
for(int j=0;j<=i;++j)
for(int k=-2;k<=2;++k){
int d=j+k;if(d<0)continue;
if(f[j][k][0]){
if(str[i]!='A')Up(g[j][min(j+2,d+1)-j][0],f[j][k][0]);
if(str[i]!='B')Up(g[d][min(j+1,d+1)-d][1],f[j][k][0]);
}if(f[j][k][1]){
if(str[i]!='B')Up(g[j][min(j+2,d+1)-j][1],f[j][k][1]);
if(str[i]!='A')Up(g[d][min(j+1,d+1)-d][0],f[j][k][1]);
}
}
for(int j=0;j<=i;++j)memcpy(h[j],t[j],sizeof(h[j]));
}int ans=0;
for(int i=0;i<=m;++i)
for(int j=-2;j<=2;++j)
if(i+1<=m||i+j+1<=m)
Up(ans,f[i][j][0]),Up(ans,f[i][j][1]);
cout<<ans<<endl;
return 0;
}
浮世苍茫,不过瞬逝幻梦
善恶爱诳,皆有定数
于命运之轮中
吞噬于黄泉之冥暗
呜呼,吾乃梦之戍人
幻恋之观者
唯于万华镜中,永世长存

浙公网安备 33010602011771号