题目链接:https://www.luogu.com.cn/problem/P1052
方程比较好像:
设f[i]表示跳到第i个点的最少石子数。
那么f[i]=min(f[i],f[i-j]+vis[i]),vis[i]代表第i个点有没有石子,s<=j<=t。
但是这样的话f的下标大小应为1e9,显然不可能。所以要进行离散化。
如果两点之间的距离小于t,那么可以让距离%t,然后再加t(因为两个点可能本来距离为t的倍数,一取模则就当成了同一个点),再用上一个点的左标加上这个距离,即为当前点的坐标。
这样就可以将数组的下标的范围压小,转移相同。
AC代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=1005; 7 int l,s,t,m,cnt; 8 int ans=0x7f7f7f; 9 int a[N],d[N],vis[N],f[N]; 10 int main(){ 11 memset(f,0x7f7f7f,sizeof(f)); 12 scanf("%d%d%d%d",&l,&s,&t,&m); 13 for(int i=1;i<=m;i++) scanf("%d",&a[i]); 14 a[m+1]=l; 15 sort(a,a+m+2); 16 for(int i=1;i<=m+1;i++) d[i]=a[i]-a[i-1]; 17 for(int i=1;i<=m+1;i++){ 18 if(d[i]>t) cnt+=d[i]%t+t; 19 else cnt+=d[i]; 20 vis[cnt]=1; 21 } 22 f[0]=0; 23 for(int i=1;i<=cnt+t-1;i++){ 24 for(int j=s;j<=t;j++){ 25 if(i-j>=0) f[i]=min(f[i],f[i-j]+vis[i]); 26 } 27 } 28 for(int i=cnt;i<=cnt+t-1;i++) ans=min(ans,f[i]); 29 printf("%d",ans); 30 return 0; 31 }