[bzoj1700]: [Usaco2007 Jan]Problem Solving 解题
不能贪心!不能贪心!不能贪心!
反正有反例(有的题目月初支付款很少,月末支付款很大,和前面的题凑到一个月的话可能导致下个月写不了= =这时放后一个月,和后面的题一起开始写可能更优)
比如:
50 4
40 1
5 10
43 30
1 10
老老实实DP吧。。。f[i][j]表示在第i月过后,共解决了j道题,第i月结余(可用于下个月的月初支付)的最大值。cost0[]、cost1[]分别表示月初支付和月末支付
f[i][j]=max{m-sum(cost1[k+1]....cost1[j])},(前提是sum(cost0[k+1]....cost0[j])<=f[i-1][k]且sum(cost1[k+1]....cost1[j])<=m)。
数组滚动一下。。。时间复杂度O(P^3)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 using namespace std; 5 const int maxn=305; 6 int a[maxn],b[maxn],prea[maxn],preb[maxn]; 7 short f[2][maxn]; 8 int i,j,k,n,m,pre,now,nowrest,next,s1,s2,ans; 9 bool flag; 10 11 int ra;char rx; 12 inline int read(){ 13 rx=getchar();ra=0; 14 while(rx<'0'||rx>'9')rx=getchar(); 15 while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra; 16 } 17 int main(){ 18 m=read();n=read(); 19 for(i=1;i<=n;i++)a[i]=read(),b[i]=read(),prea[i]=prea[i-1]+a[i],preb[i]=preb[i-1]+b[i]; 20 nowrest=m;ans=1; 21 memset(f[1],255,(n+1)<<1);f[1][0]=m;pre=1;now=0; 22 while(1){ 23 ans++; 24 memset(f[now],255,(n+1)<<1); 25 for(i=0;i<=n;i++){ 26 flag=0; 27 for(j=i;j>=0&&preb[i]-preb[j]<=m;j--) 28 if(prea[i]-prea[j]<=f[pre][j]){f[now][i]=m-preb[i]+preb[j];flag=1;break;} 29 if(!flag)break; 30 } 31 if(i>n)break; 32 swap(now,pre); 33 } 34 printf("%d\n",ans+1); 35 return 0; 36 }