JZYZOJ1445 [noip2014day1-T3]飞扬的小鸟 动态规划 完全背包
http://172.20.6.3/Problem_Show.asp?id=1445
很容易看出来动态规划的本质,但是之前写的时候被卡了一下(不止一下),还是写一下题解。
直接暴力O(n*m^2)大概是70分,比较划算。
100分需要对上升下降方式找规律然后优化到O(nm);
可以看出,70分算法有很多时间浪费在没必要的上升计算上,为了减少上升计算,我们可以在预处理后把上升计算变为只有一次。
把下降的放在最后处理。
观察可以发现f[i][x]的赋值只可能来自于下面升上来的,其实本质就是一个有一点特殊的完全背包,然后背包处理就可以了。(不一定要像我那样写的,我觉得其实有更好看更容易懂的写法)
最后再处理一个下降的方案比较后赋值。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<iostream> 6 using namespace std; 7 const int maxn=10010; 8 int n,m,k; 9 int a[maxn][2]={}; 10 int f[maxn][1010]={},g[1010]={}; 11 int d[maxn]={}; 12 struct nod{ 13 int p,l,h; 14 }e[maxn]; 15 bool mmp(nod aa,nod bb){ 16 return aa.p<bb.p; 17 } 18 int main(){ 19 //freopen("wtf.in","r",stdin); 20 scanf("%d%d%d",&n,&m,&k); 21 for(int i=1;i<=n;i++){ 22 scanf("%d%d",&a[i][0],&a[i][1]); 23 } 24 for(int i=1;i<=k;i++){ 25 scanf("%d%d%d",&e[i].p,&e[i].l,&e[i].h); 26 }sort(e+1,e+1+k,mmp); 27 for(int i=1;i<=k;i++){ 28 d[e[i].p]=i; 29 } 30 memset(f,63,sizeof(f)); 31 int ans=f[1][1],cnt=f[1][1]; 32 for(int i=1;i<=m;i++)f[0][i]=0; 33 int w=0; 34 for(int i=0;i<n;i++){ 35 int mi=1,ma=m; 36 if(d[i]){ 37 mi=e[d[i]].l+1,ma=e[d[i]].h-1; 38 } 39 int ff=0; 40 memset(g,63,sizeof(g)); 41 for(int j=mi;j<=ma;j++){ 42 g[j]=f[i][j]; 43 if(f[i][j]!=cnt)ff=1; 44 } 45 for(int j=1;j<=m;j++){ 46 int x=min(m,a[i+1][0]+j); 47 g[x]=min(g[x],g[j]+1); 48 } 49 for(int j=1;j<=m;j++){ 50 int x=min(m,a[i+1][0]+j); 51 f[i+1][x]=min(f[i+1][x],g[j]+1); 52 } 53 for(int j=mi;j<=ma;j++){ 54 if(j-a[i+1][1]>0) f[i+1][j-a[i+1][1]]=min(f[i+1][j-a[i+1][1]],f[i][j]); 55 } 56 if(!ff){ 57 printf("0\n%d\n",w); 58 return 0; 59 } 60 if(d[i])w++; 61 } 62 for(int i=1;i<=m;i++){ 63 ans=min(ans,f[n][i]); 64 } 65 printf("1\n%d\n",ans); 66 return 0; 67 }