木棍分割-dp,前缀和优化
木棍分割-dp,前缀和优化
题意
有 \(n\) 根木棍,给出长度,要分成 \(m\) 段,问总长度最大的一段最小长度是多少,并求出其方案数对 \(10007\) 取模的结果。
思路
第一问很容易想到用二分,第二问也比较容易想到用 \(dp\) 。二分怎么做这里不做赘述。
考虑 \(dp\) ,我们要满足长度最小,且分出来的段数小于 \(m+1\) ,很容易设计出一维给段数,一维放长度不合适,但是可以存已经做到哪里,也就是 \(dp[i][j]\) 表示到 \(i\) 分出 \(j\) 块的方案数。
状态转移:
\[dp_{i,j} = \sum_{len_j-len_k \leq milen} dp_{i-1,k}
\]
此时两层枚举加上找 \(k\) 时间复杂度 \(O(n^3)\) ,发现找 \(k\) 可以用前缀和优化,而且长度只会递增所以我们可以预处理出每个点的 \(k\) 。空间还要压一下。
code
#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn = 5e4+10;
constexpr int mod = 1e4+7;
void read(int &);
int n,m;
int li[maxn];
int dp[maxn],sum[maxn],st[maxn];
int sumdp[maxn];// 对对应dp作前缀和
inline void add(int &x,const int y)
{
x+=y;
if(x>=mod)
{
x-=mod;
}
else if(x<0)
{
x+=mod;
}
}
bool check(int x)
{
int cnt=0,len=0;// cnt=1-wa..
for(int i=1;i<=n;++i)
{
if(li[i]>x) return 0;
if(len+li[i]>x)
{
++cnt;
len=li[i];
}
else
{
len+=li[i];
}
if(cnt>m)
{
return 0;
}
}
return 1;
}
int binary(int l,int r)
{
int mid,ans=0;
while(l<=r)
{
mid=l+((r-l)>>1);
if(check(mid))
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
return ans;
}
int _dp(int x)
{
for(int i=1,id=1;i<=n;++i)// 预处理k
{
if(sum[i]<=x)
{
dp[i]=1;// dp[i][1]
}
while(id<=n && sum[i]-sum[id]>x)
{
++id;
}
st[i]=id;
}
for(int i=1;i<=n;++i)// dp[i]的前缀和
{
add(sumdp[i],sumdp[i-1]+dp[i]);
}
int ret=0;
for(int i=2;i<=m+1;++i)
{
for(int j=1;j<=n;++j)
{
dp[j]=sumdp[j-1];// 上一个dp的综合
if(st[j]-1>=0) // 存在
{
add(dp[j],-sumdp[st[j]-1]);// 减去dp_lst[st-1]
}
}
for(int j=1;j<=n;++j)
{
sumdp[j]=0;//前缀和
add(sumdp[j],sumdp[j-1]+dp[j]);
}
add(ret,dp[n]);
}
return ret;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("cjdl.in","r",stdin);
freopen("cjdl.out","w",stdout);
#endif // ONLINE_JUDGE
read(n);
read(m);
for(int i=1;i<=n;++i)
{
read(li[i]);
sum[i]=sum[i-1]+li[i];
}
int len=binary(1,sum[n]);
printf("%lld ",len);
int ans=_dp(len);
printf("%lld\n",ans);
return 0;
}
inline void read(int &x)
{
x=0;
int f=1;
signed c=getchar();
while(!isdigit(c))
{
if(c=='-')
{
f=-1;
}
c=getchar();
}
while(isdigit(c))
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
x*=f;
}

浙公网安备 33010602011771号