【NOIP2014】飞扬的小鸟
设 f[i][j]表示在坐标(i,j)点时的最小点击屏幕次数。
DP方程为 f[i][j]=min(f[i-1][j-x[i-1]]+1,f[i][j-x[i-1]]+1,f[i-1][j+y[i-1]]);
分别表示点击一次,点击多次和下降的情况。
实现方案如下:
首先全部赋最大值
然后处理一次点击和连续点击,注意到了上界需要特殊的搞一下
再处理下落的情况
处理完后记得把柱子的f赋为最大值
然后最后扫一遍判断答案
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cctype>
#include<cfloat>
#include<vector>
#include<map>
using namespace std;
const int maxn=10000+10;
const int maxm=1000+10;
const int INF=100000000;
int f[maxn][maxm];
int x[maxn],y[maxn],down[maxn],up[maxn];
int main()
{
freopen("!.in","r",stdin);
freopen("!.out","w",stdout);
int n,m,a;
cin>>n>>m>>a;
for(int i=0;i<n;i++)
scanf("%d%d",&x[i],&y[i]);
for(int i=1;i<=n;i++)
{down[i]=0;up[i]=m+1;}
int p,l,h;
for(int i=0;i<a;i++){
scanf("%d%d%d",&p,&l,&h);
down[p]=l;up[p]=h;
}
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
f[i][j]=INF;
f[0][0]=INF;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
if(j>=x[i-1]){
f[i][j]=min(f[i][j],f[i-1][j-x[i-1]]+1);
f[i][j]=min(f[i][j],f[i][j-x[i-1]]+1);
}
for(int j=m-x[i-1];j<=m;j++)
{
f[i][m]=min(f[i][m],f[i-1][j]+1);
f[i][m]=min(f[i][m],f[i][j]+1);
}
for(int j=down[i]+1;j<=up[i]-1;j++)
if(j+y[i-1]<=m)
f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]);
for(int j=1;j<=down[i];j++) f[i][j]=INF;
for(int j=up[i];j<=m;j++) f[i][j]=INF;
}
int ans=INF,num=a;
for(int i=n;i>=1;i--)
{
for(int j=down[i]+1;j<up[i];j++)
ans=min(ans,f[i][j]);
if(ans!=INF) break;
if(up[i]<=m) num--;
}
if(num==a) printf("1\n%d",ans);
else printf("0\n%d",num);
return 0;
}

浙公网安备 33010602011771号