AT_s8pc_4_e Enormous Atcoder Railroad 题解
我们肯定会先坐地铁,因此考虑每个地铁之间怎么设立公交点。
题目要求我们计算有几种设置方法,因此考虑 dp。我们先坐了地铁,那么之后就只会坐公交了,所以对于每个地铁站之间的地段可以单独讨论,最后用乘法原理计算。
对于不同的段,我们除了长度不同,还有左右两端可以走的长度不同。
在起始状态下,我们从右边来能够走的距离比从左边来的情况少一格。
考虑我们如何设置站台选择,如果我们直接从左往右放,容易忽略从右边来的情况,不利于计算。
由于两边的可走长度不同,对计算影响较大,我们考虑把可走长度放到状态中。
如果仅仅记录左右两边的长度,那么会出现我放了一个位置但是不知道收缩左边还是右边的情况,非常麻烦。
所以考虑类似求最短路的算法,我们先把可以走的更远的,也就是消耗更少的放了。
由于起始时右边可走长度更短,所以先放左边,再放右边,以此类推,这样我们只需要记录左边或者右边长度以及当前左右是否相等即可得到两边的可走长度。
这样状态中只需要记录目前两边的距离,某一边的可走长度,左右可走长度是否相等。
直接 dp 再通过前缀和优化即可。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,k,x,dp[10005][2],s[2505],pre[10005];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>k>>x;
for(int i=1;i<=k;i++)cin>>s[i];
if(x<k){
cout<<0;
return 0;
}
int op=0;
int ans=1;
for(int i=0;i<=x;i++){
op^=1;
for(int j=1;j<=10000;j++){
if(j<=i*2)dp[j][0]=1;
else dp[j][0]=0;
if(min(j-1,i*2))dp[j][0]=(0ll+dp[j][0]+mod+pre[j-1]-pre[j-min(j-1,i*2)-1])%mod;
}
for(int j=1;j<=10000;j++)pre[j]=(pre[j-1]+dp[j][0])%mod;
for(int j=1;j<=10000;j++){
if(j<=i*2+1)dp[j][1]=1;
else dp[j][1]=0;
if(min(j-1,i*2))dp[j][1]=(0ll+dp[j][1]+mod+pre[j-1]-pre[j-min(j-1,i*2)-1])%mod;
}
for(int j=1;j<=10000;j++)pre[j]=(pre[j-1]+dp[j][1])%mod;
int id=x+1-i;
if(i>=x-k+2)ans=1ll*ans*dp[s[id+1]-s[id]][0]%mod;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号