P1912 [NOI2009] 诗人小G 分析

news/2025/10/15 22:22:01/文章来源:https://www.cnblogs.com/high-sky/p/19144408

题目链接:P1912 [NOI2009] 诗人小G

题目概述

给你几个字符串,你可以按照给定的顺序任意拼接(你可以分组),但是拼接的时候中间要打空格,设这个当前的拼接长度为 \(sum\),那么代价为 \(|sum-L|^P\),求最小的代价并输出方案。

分析

Luogu题解告诉我们一个快速判断决策单调性的办法:https://www.luogu.com.cn/article/38xahpje。

首先能够决策单调性优化的 \(dp\) 是:\(f_i=\min f_j+w(j,i)\),最优决策点为 \(p_i\),若都满足 \(p_i\leq p_{i+1}\) 那么就满足决策单调性。

设决策点为 \(j\) 的函数 \(f_j(x)=f_j+w(j,x)\),假设两个决策点 \(j<l\),如果 \(f_j(x)\)\(f_l(x)\) 有且仅有一个交点,那么其满足决策单调性。

步入正题。

首先显然:

\[f_i=\min_{j\in[0,i-1]}f_j+|sum_i-sum_j-1-L|^P \]

我们感性理解一下就知道这满足决策单调性(你也可以打表证明)。

虽然说这道题目是一道经典题,我们还是要记录许多 trick 的。

传统的决策单调性二分队列写法十分的骚气。

按照以下过程执行:

队列中每一个值存三个状态 \((k,l,r)\),代表决策点 \(k\)\([l,r]\) 有效。

对于队头中 \(r\geq i\) 的弹出。

然后用队头进行转移。

对于当前决策点 \(i\),如果后面队尾的 \(l\) 决策都比我菜,那你也没有存在的必要了。如果只是 \(r\) 比我菜,那么我们二分这个然后分别赋值就可以了。

我们发现有些 \(l,r\) 是不是没有必要,我们只需要维护相邻两个决策点的临界值即可。

对于此题,我们有可能爆 long long,可以通过精度(long double)来换取。

代码

时间复杂度 \(\mathcal{O}(n\log n\log P)\)

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define int long long
#define ld long double
#define N 100005
using namespace std;
#define abs(x) ((x) < 0 ? -(x) : (x))
#define isdigit(ch) ('0' <= ch && ch <= '9')
template<typename T>
void read(T&x) {x = 0;char ch = getchar();for (;!isdigit(ch);ch = getchar());for (;isdigit(ch);ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
}
template<typename T>
void write(T x) {if (x > 9) write(x / 10);putchar(x % 10 + '0');
}
ld qpow(ld a,int b) {ld res = 1;while(b) {if (b & 1) res *= a;a *= a;b >>= 1;}return res;
}
int T,len[N],n,P,L,sum[N],q[N],p[N],pre[N];
ld f[N];
string s[N];
ld calc(int i,int j) {return f[j] + qpow(abs(sum[i] - sum[j] - L),P);
}
int find(int x,int y) {int l = x,r = n + 1,res = n + 1;while (l <= r) {int mid = l + r >> 1;if (calc(mid,x) >= calc(mid,y)) res = mid,r = mid - 1;else l = mid + 1;}return res;
}
signed main(){read(T);for (;T --;) {read(n),read(L),read(P);L ++;for (int i = 1;i <= n;i ++) {cin >> s[i];len[i] = s[i].size();}for (int i = 1;i <= n;i ++) sum[i] = sum[i - 1] + len[i] + 1,f[i] = 1e18 + 5;f[0] = 0;int head = 1,tail = 0;q[++tail] = 0;for (int i = 1;i <= n;i ++) {while(head < tail && p[head] <= i) head ++;f[i] = calc(i,q[head]);pre[i] = q[head];while(head < tail && p[tail - 1] >= find(q[tail],i)) tail --;p[tail] = find(q[tail],i);q[++tail] = i;}if (f[n] > 1e18) puts("Too hard to arrange");else {write((int)(f[n] + 0.5)),putchar('\n');int now = n;vector<string> ls;while(now) {ls.push_back("");for (int i = now;i > pre[now];i --)ls.push_back(s[i]);now = pre[now];}reverse(ls.begin(),ls.end());bool flag = 0;for (auto i : ls) {if (i == "") putchar('\n'),flag = 0;else {if (flag) putchar(' ');cout << i;flag = 1;}}}puts("--------------------");}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/937845.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[COCI2022-2023#2] Tramvaji 题解

简要题意 告诉一些站点之间的距离,求两站距离最小的两个站 思路 对于某个站点,站台1到他前面的站的距离一定已经处理好了,所以可以用一个数组维护前缀和,从前面某个站转移过来,最后统计就行了 Code: #include <…

一级指针和二级指针作为函数参数的区别

在函数参数中,一级指针(int*)和二级指针(int**)的核心区别在于能修改的数据层级:一级指针可修改指针指向的变量值,而二级指针可修改一级指针本身(包括其指向或分配的内存) 一级指针作为函数参数 作用:通过一…

ROUGE指标

2025.10.15 1.ROUGE指标是评估文本生成质量的常用指标,通过计算生成文本与参考文本之间的n-gram重叠度来测量内容相似性和召回率

CSP-S 模拟 29

CSP-S 模拟 29 A. 一个赢家 (card) 有 \(2n\) 张卡,第 \(i\) 张卡上写着数字 \(i\)。有 \(n\) 个人,这 \(n\) 个人轮流从这些卡中均匀随机拿走两张,不放回。现在每个人手上各有两张卡,手上两张卡上写的数字的和最大…

实用指南:【编号508】(道路分类)湖南路网数据湖南路网分类数据(2025年)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Linux 文件及相关安全操作指南

Linux 文件及相关安全操作指南 Linux根目录项一行说明 一、Linux 根目录各文件夹一行说明(基础回顾)根目录文件夹 一行核心用途bin 系统启动与普通用户可用的基础可执行程序(如ls、cp)boot 启动相关文件(内核vmli…

day012

今日完成:学习了mysql的数据库编辑,添加. 明日完成:数据库 遇到问题:无

怎么能把一个横着的很长的excel表,输出成一个能完整展示在一个页面中的PDF

参考链接:https://blog.csdn.net/qq_34972627/article/details/128139320 横向的Excel输出为pdf自动分成两页怎么办?不分页,铺满整张纸的方法来了

深入解析:Leetcode+Java+图论+岛屿问题

深入解析:Leetcode+Java+图论+岛屿问题pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mo…

简单介绍

简单介绍AI Agent 即人工智能体,通常是指有能力主动思考和行动的智能体,能够以类似人类的方式工作,通过大模型来 “理解” 用户需求,主动 “规划” 以达成目标,使用各种 “工具” 来完成任务,并最终 “行动” 执…

agent认知与原理分析

agent认知与原理分析1

agent策略分析与Parer解读

agent策略分析与Parer解读1

夸克网盘免费扩容,新用户轻松领取1TB免费空间!一步一步教你如何操作! - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Visual Studio 2022连接mysql数据库,解决System.Data.Odbc.OdbcException (0x80131937)

首先我们要下载MySQL ODBC驱动,下载地址: https://downloads.mysql.com/archives/c-odbc/ 下载Windows (x86, 64-bit), MSI Installer 了解ODBC:接下来要连接mysql数据库了,参考这位前辈的笔记:https://blog.csdn…

[AI生成]Spark-TTS个人理解

Spark-TTS 是一个在设计思路上非常清晰、工程结构合理、适合个人开发者学习和二次开发的优秀开源 TTS 项目。以下是它值得肯定的几个关键点,也解释了为什么它特别适合学习:✅ 为什么 Spark-TTS 适合个人开发者学习?…

2025.10.3 测试

DP+线段树/容斥+DP/贪心+构造/Ad-hocA. 思考如何匹配子序列,肯定是贪心的能扩展就扩展,将这个过程改写成 DP 。 设 \(f[i, j]\) 表示 \(S\) 匹配了 \(i\) 位,\(T\) 匹配了 \(j\) 位的方案数。 枚举下一位匹配位置得…

[20251015]建立和完善col_vlist.sql脚本.txt

[20251015]建立和完善col_vlist.sql脚本.txt--//建立一个支持视图的版本,由于oracle没有视图提取字段信息的视图,只能通过desc提取,通过bash shell处理生成需要的脚本。--//如果有哪个视图支持提取视图字段信息的,…

[20251014]建立和完善col_list.sql脚本.txt

[20251014]建立和完善col_list.sql脚本.txt--//增加选择字段顺序号功能。$ cat col_list.sql-- Copyright 2023 lfree. All rights reserved.-- Licensed under the Apache License, Version 2.0. See LICENSE.txt for…

[20251014]建立完善通用的prx.sql脚本.txt

[20251014]建立完善通用的prx.sql脚本.txt--//前几天更改了tpt的prr.sql,想实现一个更加通用pr.sql的版本。自己做一些尝试:--//参数1支持2种格式,第1种格式使用数字序列使用,分开,输出对应字段。第2种格式使用正则…