luogu1941 [NOIp2014]飞扬的小鸟 (dp)

设f[i][j]为到达(i,j)这个位置的最小操作数

就有$f[i][j]=min\{f[i-1][j+Y[i-1]],f[i-1][j-X[i-1]*k]+k\}$

然后考虑优化一下转移:

对于一系列模x[i-1]相同的高度,它们都可以转移到模x[i-1]相同的高度、而且在它们上边的点,所以只要从下往上做,不断地取一个最小值就可以了(会意 会意...)

要注意的是不管怎么操作,只要操作完高度>M都会变成=M,而且还可以从M点一下还维持在M

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define lowb(x) ((x)&(-(x)))
 4 #define REP(i,n0,n) for(i=n0;i<=n;i++)
 5 #define PER(i,n0,n) for(i=n;i>=n0;i--)
 6 #define MAX(a,b) ((a>b)?a:b)
 7 #define MIN(a,b) ((a<b)?a:b)
 8 #define CLR(a,x) memset(a,x,sizeof(a))
 9 #define rei register int
10 using namespace std;
11 typedef long long ll;
12 const int maxn=10010,maxm=1010;
13 
14 inline ll rd(){
15     ll x=0;char c=getchar();int neg=1;
16     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
17     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
18     return x*neg;
19 }
20 
21 int N,M,K;
22 int x[maxn],y[maxn];
23 int f[2][maxm],l[maxn],h[maxn],ans=1,cnt;
24 bool istube[maxn];
25 
26 int main(){
27     // freopen("testdata.in","r",stdin);
28     rei i,j,k;
29     N=rd(),M=rd(),K=rd();
30     for(i=0;i<N;i++) x[i]=rd(),y[i]=rd();
31     for(i=0;i<=N;i++) l[i]=1,h[i]=M*2;
32     for(i=1;i<=K;i++){
33         int a=rd(),b=rd(),c=rd();
34         istube[a]=1;
35         l[a]=b+1;h[a]=c-1;
36     }
37     CLR(f,127);CLR(f[0],0);
38     bool b=1;
39     for(i=1;i<=N&&ans;i++){
40         CLR(f[b],127);
41         for(j=l[i];j<=min(M,h[i])&&j+y[i-1]<=min(M,h[i-1]);j++){
42             if(j+y[i-1]>=l[i-1]) f[b][j]=f[b^1][j+y[i-1]];
43         }
44         for(j=l[i-1];j<l[i-1]+x[i-1]&&j<=min(M,h[i-1]);j++){
45             int mm=f[b^1][j];
46             // printf("!%d %d\n",j,mm);
47             for(k=1;j+x[i-1]*k<=h[i];k++){
48                 int jk=j+x[i-1]*k;
49                 // printf("!!!%d %d\n",jk,mm);
50                 bool re=0;
51                 if(jk>M) jk=M,re=1;
52                 if(jk>=l[i]) f[b][jk]=min(f[b][jk],mm+1);
53                 ++mm;mm=min(mm,f[b^1][jk]);
54                 if(re) break;
55             }
56         }
57         for(ans=0,j=l[i];j<=h[i];j++){
58             // printf("%d %d %d\n",i,j,f[b][j]);
59             if(f[b][j]<=1e8) {ans=1;break;}
60         }
61         if(ans&&istube[i]) cnt++;
62         b^=1;
63     }
64     printf("%d\n",ans);
65     if(ans){
66         ans=1e8;
67         for(i=l[N];i<=min(M,h[N]);i++) ans=min(ans,f[b^1][i]);
68         printf("%d\n",ans);
69     }else{
70         printf("%d\n",cnt);
71     }
72     return 0;
73 }

 

转载于:https://www.cnblogs.com/Ressed/p/9703780.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值