题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044
前缀和优化。
但开成long long会T。(仔细一看不用开long long)
#include<iostream> #include<cstdio> #include<cstring> #define ll long long using namespace std; const int N=5e4+5,M=1005; const ll mod=10007; int n,m,a[N],pos[N]; ll dp[N],l,r,lm,s[N],c[N],ans; void init() { while(l<=r) { ll mid=((l+r)>>1),sum=0;int cnt=1; for(int i=1;i<=n;i++) { if(sum+a[i]>mid) { sum=a[i];cnt++; } else sum+=a[i]; } if(cnt-1>m)l=mid+1;//分段,故cnt-1 else lm=mid,r=mid-1; } printf("%lld ",lm);// } void pre() { for(int i=1;i<=n;i++) { if(s[i]>lm)break;dp[i]=1;//dp:把前i个分成_段的方案数 } int now=0; for(int i=1;i<=n;i++) if(s[i]>lm) { while(s[i]-s[now]>lm)now++; pos[i]=now;//pos:本段首个的前一个 } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]),l=max(l,(long long)a[i]),s[i]=s[i-1]+a[i];r=s[n]; init();pre(); while(m--)//已有分成1段的方案数,再来m次 { for(int i=1;i<=n;i++)c[i]=(c[i-1]+dp[i])%mod;//c:dp的前缀和 for(int i=1;i<=n;i++)dp[i]=((c[i-1]-c[max(0,pos[i]-1)])%mod+mod)%mod;//pos[i]-1:c[pos[i]]符合 (ans+=dp[n])%=mod; } printf("%lld",ans); return 0; }
而且如果输出的 lm 改成 lm%mod ,就会WA。只开int就都好啦。(为什么?)
那个处理pos的地方很好。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=5e4+5,mod=10007; int n,m,a[N],pos[N],dp[N],l,r,lm,s[N],c[N],ans; void init() { while(l<=r) { int mid=((l+r)>>1),sum=0,cnt=1; for(int i=1;i<=n;i++) { if(sum+a[i]>mid) { sum=a[i];cnt++; } else sum+=a[i]; } if(cnt-1>m)l=mid+1; else lm=mid,r=mid-1; } printf("%d ",lm); } void pre() { for(int i=1;i<=n;i++) { if(s[i]>lm)break;dp[i]=1;//dp:把前i个分成_段的方案数 } int now=0; for(int i=1;i<=n;i++) if(s[i]>lm) { while(s[i]-s[now]>lm)now++; pos[i]=now;//pos:本段首个的前一个 } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]),l=max(l,a[i]),s[i]=s[i-1]+a[i];r=s[n]; init();pre(); while(m--)//已有分成1段的方案数,再来m次 { for(int i=1;i<=n;i++)c[i]=(c[i-1]+dp[i])%mod;//c:dp的前缀和 for(int i=1;i<=n;i++)dp[i]=((c[i-1]-c[max(0,pos[i]-1)])%mod+mod)%mod;//pos[i]-1:c[pos[i]]符合 (ans+=dp[n])%=mod; } printf("%d",ans); return 0; }