BZOJ1700: [Usaco2007 Jan]Problem Solving 解题
每月m<=1000块钱,有n<=300道题,要按顺序做,每月做题要花钱,花钱要第一个月预付下个月立即再付一次,给出预付和再付求最少几个月做完题,第一个月不做。
神奇的DP。。竟没想出来。。
注意到这个月做题受制于上个月做的题,f[i][j]--最后做i~j题的最少月数,f[i][j]=inf(i~j不能在一个月内做完)min(f[k][i-1]+2)(做k~i-1题后再付后不能在该月立即做i~j)min(f[k]i-1]+1)(k~i-1题后再付后可立即做i~j)
括号里的判断用前缀和即可。注意判断能不能一个月做完要考虑再付!!
感谢数据http://blog.sina.com.cn/s/blog_8d5d2f0401017kfk.html
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 //#include<iostream> 5 using namespace std; 6 7 int n,m; 8 #define maxn 311 9 int f[maxn][maxn],a[maxn],b[maxn],sa[maxn],sb[maxn]; 10 const int inf=0x3f3f3f3f; 11 int main() 12 { 13 scanf("%d%d",&m,&n);sa[0]=sb[0]=0; 14 for (int i=1;i<=n;i++) 15 { 16 scanf("%d%d",&a[i],&b[i]); 17 sa[i]=sa[i-1]+a[i]; 18 sb[i]=sb[i-1]+b[i]; 19 } 20 for (int i=1;i<=n;i++) if (sa[i]<=m && sb[i]<=m) f[1][i]=3;else f[1][i]=inf; 21 for (int j=2;j<=n;j++) 22 for (int i=2;i<=j;i++) 23 { 24 f[i][j]=inf;int tmp=sa[j]-sa[i-1]; 25 if (tmp<=m && sb[j]-sb[i-1]<=m) for (int k=1;k<i;k++) 26 { 27 if (sb[i-1]-sb[k-1]+tmp>m) 28 f[i][j]=min(f[i][j],f[k][i-1]+2); 29 else f[i][j]=min(f[i][j],f[k][i-1]+1); 30 } 31 } 32 int ans=inf; 33 for (int i=1;i<=n;i++) ans=min(ans,f[i][n]); 34 printf("%d\n",ans); 35 return 0; 36 }