令f[i][j]表示飞翔到(i,j)的最小点击次数
f[i][j]=min(f[i-1][j-k*x[i-1]+k,f[i-1][j+y[i-1]]
这样做复杂度O(n^2m)
考虑优化这个过程,先考虑上升的情况,则f[i][j]有两类决策转移:
1.f[i][j]=f[i-1][j-x[i-1]]
2.f[i][j]=min(f[i-1][j-k*x[i-1]]+k)
第二类的答案已经被记入f[i][j-x[i-1]]中,这样可以得到新的转移方程:f[i][j]=min(f[i][j],min(f[i−1][j−x[i−1]],f[i][j−y[i−1]])+1)
根据题目要求,转移时要先处理上升,后处理下降
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
struct ios{
//The template of Mingrui Sheng
inline char gc(){
static const int IN_LEN=1<<18|1;
static char buf[IN_LEN],*s,*t;
return (s==t)&&(t=(s=buf)+fread(buf,1,IN_LEN,stdin)),s==t?-1:*s++;
}
template <typename _Tp> inline ios & operator >> (_Tp&x){
static char ch,sgn;ch=gc(),sgn=0;
for(;!isdigit(ch);ch=gc()){if(ch==-1)return *this;sgn|=ch==‘-‘;}
for(x=0;isdigit(ch);ch=gc())x=x*10+(ch^‘0‘);
sgn&&(x=-x); return *this;
}
//Orz 浮尘ii*
}io;
int n,m,k,ans=1<<30,x[10005],y[10005],l[10005],r[10005],f[10005][2005],xx,yy,zz;
bool ok[10005];
int main(){
memset (f,0x3f3f3f3f,sizeof (f));
io>>n>>m>>k;//scanf ("%d%d%d",&n,&m,&k);
for (register int i=1;i<=n;++i){
io>>x[i]>>y[i];
l[i]=1;r[i]=m;
}
for (register int i=1;i<=k;++i){
io>>xx>>yy>>zz;
ok[xx]=1;
l[xx]=yy+1;r[xx]=zz-1;
}
for (register int i=1;i<=m;++i) f[0][i]=0;
for (register int i=1;i<=n;++i){
for (register int j=x[i]+1;j<=x[i]+m;++j) f[i][j]=min(f[i-1][j-x[i]],f[i][j-x[i]])+1;
for (register int j=m+1;j<=m+x[i];++j) f[i][m]=min(f[i][m],f[i][j]);
for (register int j=1;j<=m-y[i];++j) f[i][j]=min(f[i][j],f[i-1][j+y[i]]);
for (register int j=1;j<l[i];++j) f[i][j]=0x3f3f3f3f;
for (register int j=r[i]+1;j<=m;++j) f[i][j]=0x3f3f3f3f;
}
for (register int i=1;i<=m;++i){
if (f[n][i]<ans) ans=f[n][i];
}
if (ans<0x3f3f3f3f){
printf ("1\n%d\n",ans);
return 0;
}
ans=0;
for (register int i=n;i>=1;--i){
for (register int j=1;j<=m;++j){
if (f[i][j]<0x3f3f3f3f){
for (register int k=1;k<=i;++k) if (ok[k]) ++ans;
printf ("0\n%d\n",ans);
return 0;
}
}
}
return 0;
}
原文:https://www.cnblogs.com/DFTMR/p/11809461.html