$NOIP2005$过河

\(NOIP2005\)过河

第一次见到这种类型的\(DP\)。。。

方程‘:\(f[i]=min\{f[i-j]\}+Pos[i],\)如果\(i\)处有石子,\(Pos[i]=1\)

显然会\(MLE\)。。。

我们考虑状态中那些是重复的,即我们可以通过一些技巧将其省掉的状态。

我们发现对于一个点\(x\),对于所有的\(D\),点\(x+D(D\geq T*(T+1))\)均能从\(x\)走到。

也就是说,这些状态实际上是一个状态。

所以说,我们可以将两点间距离\(\geq T*(T+1)\)的变为\(T*(T+1)\)

因为\(S,T\)很小,所以我们达到了压缩空间的目的。

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace AE86
{
	const int bufl=1<<15;
	char buf[bufl],*s=buf,*t=buf;
	inline int fetch()
	{
		if(s==t){t=(s=buf)+fread(buf,1,bufl,stdin);if(s==t)return EOF;}
		return*s++;
	}
	inline int read()
	{
		int a=0,b=1,c=fetch();
		while(!isdigit(c)) b^=c=='-',c=fetch();
		while(isdigit(c)) a=a*10+c-48,c=fetch();
		return b?a:-a;
	}
}
const int N=1e5+10;
int n,L,S,T,Dis,Sum;
int Min,Pos[N],A[N],f[N];
inline void SubTask()
{
	for(int i=1;i<=n;i++) Sum+=!(A[i]%S);
	printf("%lld\n",Sum);
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("A.in","r",stdin);
#endif
	L=AE86::read(),S=AE86::read(),T=AE86::read(),n=AE86::read();
	for(int i=1;i<=n;i++) A[i]=AE86::read(); sort(A+1,A+n+1);
	if(S==T) {SubTask();return 0;}
	for(int i=1;i<=n;i++) Dis=min(A[i]-A[i-1],1LL*90),Sum+=Dis,Pos[Sum]=1;
	Sum+=min(L-A[n],1LL*100);memset(f,0x3f,sizeof(f));Min=f[0];f[0]=0;
	for(int i=1;i<=Sum+9;i++)
		for(int j=S;j<=T;j++)
			if(i-j>=0) f[i]=min(f[i],f[i-j]+Pos[i]);
	for(int i=Sum;i<=Sum+9;i++) Min=min(Min,f[i]);
	printf("%lld\n",Min);
}
posted @ 2019-11-13 20:12  风骨傲天  阅读(99)  评论(0编辑  收藏  举报