bzoj1044 [HAOI2008]木棍分割——前缀和优化DP
Posted Zinn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1044 [HAOI2008]木棍分割——前缀和优化DP相关的知识,希望对你有一定的参考价值。
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044
咳咳...终于A了...
居然没注意到正着找pos是n方会TLE...所以要倒着找pos;
二分还写错了,改了半天...
小心前缀和取模后相减变成负数!!!!!!!!!
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const maxn=50005,mod=10007; int n,m,a[maxn],s[maxn][3],f[maxn][3],ans,mn,sum,l,r,pos[maxn]; bool pd(int x) { int s=0,cnt=0; for(int i=1;i<=n;i++) { if(s+a[i]>x) { cnt++; s=0; } s+=a[i]; } return cnt<=m;//m!! return 1; } void solve1() { r=s[n][0]; int mid=(l+r)>>1; while (l<=r) { if (pd(mid)) mn=mid,r=mid-1; else l=mid+1; mid=(l+r)>>1; } } void solve2() { for(int i=1;i<=n;i++) { if(s[i][0]<=mn)f[i][0]=1; else break; } for (int i=1;i<=n;i++) { if (s[i][0]<=mn) continue; for (int j=i-1;j>=0;j--) if (s[i][0]-s[j][0]>mn) {pos[i]=j+1;break;} // for(int j=0;j<i;j++) // if(s[i][0]-s[j][0]<=mn){pos[i]=j;break;}//TLE!!!(n方) } bool x=0; while(m--) { for(int i=1;i<=n;i++) s[i][x]=(s[i-1][x]+f[i][x])%mod;// x=!x; for(int i=1;i<=n;i++) f[i][x]=(s[i-1][!x]-s[max(pos[i]-1,0)][!x]+mod)%mod;//i-1! //pos[i]-1! //mod后小心负数!!!!! (ans+=f[n][x])%=mod; } printf("%d %d",mn,ans); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]),s[i][0]=s[i-1][0]+a[i],l=max(l,a[i]); solve1(); solve2(); return 0; }
以上是关于bzoj1044 [HAOI2008]木棍分割——前缀和优化DP的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ1044][HAOI2008]木棍分割 二分+贪心+dp+前缀和优化
BZOJ1044: [HAOI2008]木棍分割 二分+区间DP