P1912 [NOI2009] 诗人小G
题目链接
题解:
定义
算上空格的前缀和
相当于枚举上一行的结尾在哪。
可以感性理解一下,i越靠后,最优决策点j一定会往后移。
所以决策点具有单调性。我有一个简单的证明,就是列个式子,证明i向后移一位,用j转移的式子一定小于用j-1转移。
然后,维护决策单调性,这道题不能直接用分治算法(好像可以cdq,但我不会),所以我们用二分队列来做。
首先遍历到一个点先计算它的
然后更新转移点,显然我们可以通过二分确定(只考虑前面i个点)这点作为最佳决策点的区间,记录左端点,右端点直接当作
注意事项:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int t,n,L,P,l[N],sum[N],q[N],ans[N],opt[N];
long double dp[N];
string s[N];
long double ksm(long double x,int y)
{
long double an=1;
while(y)
{
if(y&1)an=an*x;
y>>=1;
x=x*x;
}
return an;
}
long double js(int j,int i)
{
return dp[j]+ksm((long double)abs(sum[i]-sum[j]-1-L),P);
}
int find(int x,int y)
{
int l=x,r=n+1,an=n+1;
while(l<=r)
{
int mid=(l+r)>>1;
if(js(x,mid)<js(y,mid))l=mid+1;
else an=mid,r=mid-1;
}
return an;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
cin>>n>>L>>P;
for(int i=1;i<=n;i++)
{
sum[i]=0;
cin>>s[i];
sum[i]=sum[i-1]+s[i].size()+1;
}
int head=1,tail=1;q[1]=0;
for(int i=1;i<=n;i++)
{
while(head<tail&&l[head]<=i)head++;//l记录下一区间的左端点即当前区间的最大值
opt[i]=q[head];
dp[i]=js(q[head],i);
while(head<tail&&l[tail-1]>=find(q[tail],i))tail--;
l[tail]=find(q[tail],i);
q[++tail]=i;
//printf("%d %lld %d %d\n",opt[i],(long long)dp[i],l[tail-1],q[tail]);
}
if(dp[n]>1e18)cout<<"Too hard to arrang"<<'\n';
else
{
cout<<(long long)dp[n]<<'\n';
int x=n,cnt=0;
ans[++cnt]=n;
while(x!=0)
{
x=opt[x];
ans[++cnt]=x;
}
for(int i=cnt;i;i--)
{
for(int j=ans[i]+1;j<=ans[i-1];j++)
{
cout<<s[j];
if(j!=ans[i-1])cout<<' ';
}
if(i!=1)cout<<'\n';
}
}
cout<<"--------------------";if(t)cout<<'\n';
}
return 0;
}
分类:
题目讲解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具