题目链接:
y总的视频讲解:AcWing484过河(视频讲解)
题面:
动态规划:
状态表示:f[x]表示到达第x位置所需踩到的最少石子数
集合:最小值
状态计算:可知对于每个x位置,都一定是前面的[S,T]的位置跳过来的.所以
f[i]=min(f[i],f[j]+a[i])(i-T<=j<=i-S).
但是这道题的L非常大.如果L<=10000的话,时间复杂度就可以过去.会发现,该题中M不大,也就是说如果把M个石子放在长度L的桥上,石子会显得非常稀疏.
所以考虑如何缩短相邻两个石子之间的距离,但却并不影响答案.
对于刚好踏过第i个石子的位置一定是在Q=[a[i].a[i]+10]之内的,而对于还未踏过第i+1个石子的位置一定是在U=[a[i+1]-10,a[i+1]]之内的.如果Q区间与U区间之间的距离长到什么程度的时候,Q区间内任意一个点都能到达U区间呢?
那么引入一个结论:若a,b互质的话.那么a与b之间无法表示的最大数字是(a-1)*(b-1)-1;
(可以看TZOJ:5996小凯的疑惑)
那么有这个结论后考虑最糟糕的情况,当T=10时,T与T-1互质,T-1与T-2互质....
所以取个最大的长度即(T-1)*(T-1-1)-1=71.所以当区间Q与区间U的距离到达71以上时,可以直接缩短到71,那么这里直接把这个长度缩到100即可.
那么最大时间复杂度就是长度L=100*M,枚举S~T=10;所以总时间=10 ^ 5;
代码:
#include <bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
int l,s,t,m;
int a[105];
int f[10005];
map<int,int> maps;
int main(){
cin>>l>>s>>t>>m;
for(int i=1;i<=m;i++) cin>>a[i];
sort(a+1,a+m+1);
if(s==t){
int ans=0;
for(int i=1;i<=m;i++)
if(a[i]%s==0)
ans++;
cout<<ans<<endl;
}
else{
a[m+1]=l;
for(int i=1,last=0,offset=0;i<=m+1;i++){
if(a[i]-last>100){
offset+=a[i]-last-100;
}
last=a[i];
a[i]-=offset;
}
l=a[m+1];
for(int i=1;i<=m;i++) maps[a[i]]=1;
memset(f,0x3f,sizeof(f));
l=a[m]+10;f[0]=0;
for(int i=0;i<=l;i++){
for(int j=s;j<=t;j++){
f[i+j]=min(f[i+j],f[i]+maps[i+j]);
}
}
int ans=inf;
for(int i=l;i<=l+t;i++)
ans=min(ans,f[i]);
cout<<ans<<endl;
}
return 0;
}