[二分][DP]JZOJ 3242 Spacing
分析
比赛的时候一看:宝崽题,然后快乐地打起了贪心……
贪心能拿70pt,血赚
正解应是从最大值最小处琢磨,可以二分加DP验证
那么先做个前缀和,方便求单词总长度
我们设f[i]表示第i个单词作为某行结尾的可能性,能为1,不能为0
显然f[0]初始化为1,其余为0
那么考虑一个可转移的j,必定满足f[j]==1
而且,s[i]-s[j]单词总长度+i-j-1用最小空格填充缝隙所需长度<=w宽度
同时满足s[i]-s[j]+mid*(i-j-1)>=w,因为你用最大空格填充,一定要能够填满
然后由于第n个单词不一定在行末,只需要满足第一个要求即可,需要特殊处理
#include <iostream> #include <cstdio> #include <memory.h> using namespace std; typedef long long ll; const int N=5e4+10; int w,n,ans; bool f[N]; ll s[N]; bool Calc(int x) { int j=0,k=j-1; memset(f,0,sizeof f); f[0]=1; for (int i=1;i<n;i++) { for (;j<i&&s[i]-s[j]+x*(i-j-1)>=w;j++) if (f[j]) k=j; f[i]=k!=-1&&s[i]-s[k]+i-k-1<=w; } for (int i=n-1;i>=0;i--) if (f[i]&&s[n]-s[i]+n-i-1<=w) return 1; return 0; } int main() { scanf("%d%d",&w,&n); for (int i=1,a;i<=n;i++) scanf("%d",&a),s[i]=s[i-1]+a; int l=1,r=w-2; while (l<=r) { int mid=l+r>>1; if (Calc(mid)) ans=mid,r=mid-1; else l=mid+1; } printf("%d",ans); }
在日渐沉没的世界里,我发现了你。