[noip2014]飞扬的小鸟 题解

其实,这道题本质实在不难,一眼可以看出dp相关,不过细节比较多。
f[i][j]表示,在i,j的最少点击数。

首先,考虑上升的情况,每次可以升随意次,那么f[i][j]=min(f[i][j-k*X[i]]+K)了,但是我们显然要去掉k,就可以采用完全背包的思路。
f[i][j]=min(f[i-1][j-X[i]],f[i][j-X[i]])+1,就好了。

下降没什么好说的,就一个0/1背包,注意柱子的范围。。

还有一点是到达顶端的,这个我们特殊处理一下,减k*X[i]就好了。

最后就是判断答案的过程了。

#include
#define N 1000
using namespace std;
int n,m,k,x;
int X[N*10+5],Y[N*10+5],A[N*10+5][2],f[N*10+5][N+5],c[N+5];
int ans;
inline char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    int x=0,b=1;
    char c=nc();
    for(;!(c<='9'&&c>='0');c=nc())if(c=='-')b=-1;
    for(;c<='9'&&c>='0';c=nc())x=x*10+c-'0';
    return x*b;
}
int main()
{
    freopen("in.txt","r",stdin);
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;i++)X[i]=read(),Y[i]=read(),A[i][0]=1,A[i][1]=m;
    for(int i=1;i<=k;i++)
    {
        x=read(),c[i]=x;
        A[x][0]=read(),A[x][1]=read();
        A[x][0]++,A[x][1]--; 
    }
    memset(f,37,sizeof(f));
    for(int i=1;i<=m;i++)f[0][i]=0;
    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],min(f[i-1][j-X[i]],f[i][j-X[i]])+1);
        for(int j=0;j<=X[i];j++)f[i][m]=min(f[i][m],min(f[i-1][m-j],f[i][m-j])+1);
        for(int j=1;j<=m;j++)
            if(A[i][0]<=j&&j<=A[i][1])
                if(j+Y[i]<=m)f[i][j]=min(f[i][j],f[i-1][j+Y[i]]);else;
            else f[i][j]=1e9;
    }
    ans=1e9;
    for(int i=1;i<=m;i++)ans=min(ans,f[n][i]);
    if(ans<1e6)return cout<<1<0;
    for(int i=1;i<=n;i++)
    {
        ans=1e9;
        for(int j=1;j<=m;j++)ans=min(ans,f[i][j]);
        if(ans>=1e6)
        {
            ans=0;
            for(int j=1;j<=k;j++)if(c[j]return cout<<0<0;
        }
    }
    return 0;
} 

你可能感兴趣的:(刷题总结,动归与递推)