Noip 2014 提高组 飞扬的小鸟

来源:互联网 发布:知乎 显微镜原理 编辑:程序博客网 时间:2024/05/16 13:46

分析

f[i][j],表示到第i列,高度为j,最少要按几次。

70分做法:dp转移方程上升f[i][j]=min{f[i-1][j-up[i]*k}+k},下降f[i][j]=min{f[i-1][j+donw[i]]},O(nm^2)

100分做法:将上升的过程优化,方程改为,f[i]j]=min{f[i-1][j-up[i]]+1},f[i][j]=min{f[i][j-up[i]]+1},O(nm)

注意在优化的时候要先让所有鸟跳完,再把有管子的地方赋为Inf,因为可能某个高度跳一次不行,但是跳两次可以,这样的情况会被漏算


代码

#include<cstdio>using namespace std;#define N 10005#define M 1005 #define inf 1000000000int up[N],down[N],x[N],s[N],f[N][M],d[N];int n,m,k,Down,Up,ok,ans,w;int max(int a,int b) {return a>b? a:b;}int min(int a,int b) {return a>b? b:a;}void swap(int &a,int &b) {int t=a;a=b;b=t;}int read(){    int x=0,f=1;char ch=getchar();    for (;ch>'9'||ch<'0';ch=getchar()) if (ch=='-') f=-1;    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';    return x*f;}int main(){    n=read(); m=read(); k=read();    for (int i=1;i<=n;i++) up[i]=read(),down[i]=read();    for (int i=1;i<=n;i++) x[i]=0,s[i]=m+1;    for (int i=1;i<=k;i++) {w=read(),x[w]=read(),s[w]=read();d[w]=1;}    for (int i=0;i<=n;i++) for (int j=0;j<=m;j++) f[i][j]=inf;     for (int i=0;i<=m;i++) f[0][i]=0;    for (int i=1;i<=n;i++)    {        for (int j=0;j<=m;j++)        if (f[i-1][j]^inf)        {                Up=j+up[i];if (Up>m) Up=m;                f[i][Up]=min(f[i][Up],f[i-1][j]+1);         }        for (int j=0;j<=m;j++)        if (f[i][j]^inf)        {        Up=j+up[i]; if (Up>m) Up=m;        f[i][Up]=min(f[i][Up],f[i][j]+1);}for (int j=0;j<=x[i];j++) f[i][j]=inf;for (int j=x[i]+1;j<s[i];j++) if (f[i][j]^inf) ok=i;for (int j=s[i];j<=m;j++) f[i][j]=inf;        for (int j=0;j<=m;j++)        if (f[i-1][j]^inf)        {            Down=j-down[i];            if (Down>0 && Down>x[i] && Down<s[i]) f[i][Down]=min(f[i][Down],f[i-1][j]),ok=i;        }     }    if (ok^n) {int ans=0;for (int i=1;i<=ok;i++)ans+=d[i];printf("0\n%d",ans);return 0;}    ans=inf;    for (int i=0;i<=m;i++) ans=min(ans,f[n][i]);     printf("1\n%d",ans);    return 0;}