Codeforces 题面传送门 & 洛谷题面传送门

学 whk 时比较无聊开了道题做做发现是道神题(

介绍一种不太一样的做法,不观察出决策单调性也可以做。

首先一个很 trivial 的 observation 是,如果 \(2^{k-1}>n\)​ 那么答案就是 \(n\)​,因为我们可以第 \(i\) 段放 \(2^{i-1}\) 个数(最后一段除外),这样每一段中,肯定只有形如 \((x,x)\) 的整数对会产生贡献,这样答案刚好取到下界 \(n\)。

我们设 \(dp_{i,j}\) 表示前 \(i\) 个数分成 \(j\) 段,它们的 \(f\) 值之和的最小值,显然 \(j\) 的上界只用取到 \(18\),因此我们计算出 \(dp_{i,j}\) 之后即可 \(\Theta(1)\) 地求出答案。至此,问题转化为如何求 \(dp_{i,j}\)。

考虑化简 \(c(l,r)\) 的表达式,一个非常浅显的性质是对于 \(\min(i,j)<l\) 的数对 \((i,j)\),必然有 \(\gcd(i,j)<l\),因此我们可以直接那拿总数 \(\dfrac{r(r+1)}{2}\) 减去 \(\gcd(i,j)\) 小于 \(l\) 的数对 \((i,j)\) 的个数,即如果我们设 \(g(n,k)=\sum\limits_{i=1}^n\sum\limits_{j=i}^n[\gcd(i,j)\le k]\),那么有 \(dp_{i,j}=\min\limits_{k}dp_{k,j-1}+\dfrac{i(i+1)}{2}-g(i,k)\)。而根据莫比乌斯反演的知识,有

\[\begin{aligned}
g(n,k)&=\sum\limits_{i=1}^n\sum\limits_{j=1}^n[\gcd(i,j)\le k]\\
&=\sum\limits_{d=1}^k\sum\limits_{i=1}^n\sum\limits_{j=i}^n[\gcd(i,j)=d]\\
&=\sum\limits_{d=1}^k\sum\limits_{i=1}^{n/d}\sum\limits_{j=i}^{n/d}[\gcd(i,j)=1]\\
&=\sum\limits_{d=1}^k\dfrac{1+\sum\limits_{p=1}^{n/d}\mu(p)\lfloor\dfrac{n}{dp}\rfloor^2}{2}
\end{aligned}
\]

考虑怎样维护之,也就是说怎样动态地对于一个决策点 \(k\),用个什么东西维护 \(dp_{k,j-1}-g(i,k)\) 的值,进而求出全局最小值。考虑线段树优化 dp。我们建立一棵线段树,并且希望,当我们动态地枚举到 \(i\) 时,线段树上下标为 \(k\) 的位置上的值就等于 \(dp_{k,j-1}-g(i,k)\),那么就有 \(dp_{i,j}=\dfrac{i(i+1)}{2}+\text{此时线段树上全局最小值}\)。

这又该怎样维护呢?我们发现这样一个性质:当 \(n\) 由 \(n-1\) 变到 \(n\) 时,只有那些 \(d\mid n\) 的 \(\sum\limits_{p=1}^{n/d}\mu(p)\lfloor\dfrac{n}{dp}\rfloor^2\) 会发生改变,也就是说,对于一个固定的 \(k\),如果我们预处理出了 \(sum_i=\sum\limits_{i=1}^n\mu(i)\lfloor\dfrac{n}{i}\rfloor\),那么我们可以在 \(\Theta(d(n))\) 的时间内计算出 \(g(n,k)-g(n-1,k)\)。具体方法就是,遍历所有 \(d\mid n\),如果 \(d\le k\),那么就会 \(g(n,k)\) 就会相较于 \(g(n-1,k)\) 产生 \(\dfrac{1+\sum\limits_{p=1}^{n/d}\mu(p)\lfloor\dfrac{n}{dp}\rfloor^2}{2}-\dfrac{1+\sum\limits_{p=1}^{(n-1)/d}\mu(p)\lfloor\dfrac{n-1}{dp}\rfloor^2}{2}\) 的增量。发现了这个性质以后就很好维护了,当我们扫描到 \(i\) 时遍历一遍所有 \(i\) 的因子 \(d\),计算出 \(\dfrac{1+\sum\limits_{p=1}^{i/d}\mu(p)\lfloor\dfrac{i}{dp}\rfloor^2}{2}-\dfrac{1+\sum\limits_{p=1}^{(i-1)/d}\mu(p)\lfloor\dfrac{i-1}{dp}\rfloor^2}{2}\),然后在线段树上执行一遍后缀减即可。

时间复杂度 \(n\ln n\log^2n\),较为卡常。

using namespace fastio;
const int MAXV = 1e5;
const int LOG_N = 18;
const int MAXC = MAXV << 4;
int pr[MAXV / 6 + 5], mu[MAXV + 5], prcnt = 0;
int smu[MAXV + 5]; ll sm[MAXV + 5];
bool vis[MAXV + 5];
int hd[MAXV + 5], val[MAXC + 5], nxt[MAXC + 5], item_n = 0;
void ins(int x, int y) {val[++item_n] = y; nxt[item_n] = hd[x]; hd[x] = item_n;}
void sieve(int n) {
mu[1] = 1;
for (int i = 2; i <= n; i++) {
if (!vis[i]) mu[i] = -1, pr[++prcnt] = i;
for (int j = 1; j <= prcnt && pr[j] * i <= n; j++) {
vis[pr[j] * i] = 1; if (i % pr[j] == 0) break;
mu[pr[j] * i] = -mu[i];
}
}
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j += i)
ins(j, i);
for (int i = 1; i <= n; i++) smu[i] = smu[i - 1] + mu[i];
for (int i = 1; i <= n; i++) {
sm[i] = sm[i - 1];
for (int e = hd[i]; e; e = nxt[e]) {
int f = val[e];
sm[i] -= 1ll * mu[f] * (i / f - 1) * (i / f - 1);
sm[i] += 1ll * mu[f] * (i / f) * (i / f);
}
}
}
ll dp[LOG_N + 2][MAXV + 5];
struct node {ll mn, lz;} s[MAXV * 4 + 5];
void pushup(int k) {s[k].mn = min(s[k << 1].mn, s[k << 1 | 1].mn) + s[k].lz;}
void build(int k, int l, int r, int lv) {
s[k].lz = 0; if (l == r) return s[k].mn = 2 * dp[lv][l], void();
int mid = l + r >> 1; build(k << 1, l, mid, lv); build(k << 1 | 1, mid + 1, r, lv);
pushup(k);
}
void tag(int k, ll v) {s[k].lz += v; s[k].mn += v;}
void modify(int k, int l, int r, int p, ll v) {
if (l >= p) return tag(k, v), void();
int mid = l + r >> 1;
if (p <= mid) modify(k << 1, l, mid, p, v), tag(k << 1 | 1, v);
else modify(k << 1 | 1, mid + 1, r, p, v);
pushup(k);
}
int main() {
sieve(MAXV); memset(dp, 0x1f, sizeof(dp)); dp[0][0] = 0;
for (int i = 1; i <= MAXV; i++) dp[1][i] = 1ll * i * (i + 1) / 2;
for (int i = 2; i <= LOG_N; i++) {
build(1, 0, MAXV, i - 1);
for (int j = 1; j <= MAXV; j++) {
for (int e = hd[j]; e; e = nxt[e]) {
int f = val[e];
ll ori = ((j / f == 1) ? 0 : 1) + sm[j / f - 1];
ll cur = 1 + sm[j / f];
modify(1, 0, MAXV, f, ori - cur);
}
dp[i][j] = ((s[1].mn + s[1].lz) / 2) + 1ll * j * (j + 1) / 2;
// printf("%d %d %lld\n", i, j, dp[i][j]);
}
}
int qu; read(qu);
while (qu--) {
int n, k; read(n); read(k);
if (k > LOG_N) print(n, '\n');
else print(dp[k][n], '\n');
}
print_final();
return 0;
}

Codeforces 1603D - Artistic Partition(莫反+线段树优化 dp)的更多相关文章

  1. Codeforces Round #426 (Div. 2) D 线段树优化dp

    D. The Bakery time limit per test 2.5 seconds memory limit per test 256 megabytes input standard inp ...

  2. D - The Bakery CodeForces - 834D 线段树优化dp···

    D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...

  3. BZOJ2090: [Poi2010]Monotonicity 2【线段树优化DP】

    BZOJ2090: [Poi2010]Monotonicity 2[线段树优化DP] Description 给出N个正整数a[1..N],再给出K个关系符号(>.<或=)s[1..k]. ...

  4. [AGC011F] Train Service Planning [线段树优化dp+思维]

    思路 模意义 这题真tm有意思 我上下楼梯了半天做出来的qwq 首先,考虑到每K分钟有一辆车,那么可以把所有的操作都放到模$K$意义下进行 这时,我们只需要考虑两边的两辆车就好了. 定义一些称呼: 上 ...

  5. 【bzoj3939】[Usaco2015 Feb]Cow Hopscotch 动态开点线段树优化dp

    题目描述 Just like humans enjoy playing the game of Hopscotch, Farmer John's cows have invented a varian ...

  6. POJ 2376 Cleaning Shifts (线段树优化DP)

    题目大意:给你很多条线段,开头结尾是$[l,r]$,让你覆盖整个区间$[1,T]$,求最少的线段数 题目传送门 线段树优化$DP$裸题.. 先去掉所有能被其他线段包含的线段,这种线段一定不在最优解里 ...

  7. 洛谷$P2605\ [ZJOI2010]$基站选址 线段树优化$dp$

    正解:线段树优化$dp$ 解题报告: 传送门$QwQ$ 难受阿,,,本来想做考试题的,我还造了个精妙无比的题面,然后今天讲$dp$的时候被讲到了$kk$ 先考虑暴力$dp$?就设$f_{i,j}$表示 ...

  8. 4.11 省选模拟赛 序列 二分 线段树优化dp set优化dp 缩点

    容易想到二分. 看到第一个条件容易想到缩点. 第二个条件自然是分段 然后让总和最小 容易想到dp. 缩点为先:我是采用了取了一个前缀最小值数组 二分+并查集缩点 当然也是可以直接采用 其他的奇奇怪怪的 ...

  9. 2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP)

    2021.12.08 P1848 [USACO12OPEN]Bookshelf G(线段树优化DP) https://www.luogu.com.cn/problem/P1848 题意: 当农夫约翰闲 ...

随机推荐

  1. 4个实验,彻底搞懂TCP连接的断开

    前言 看到这个标题你可能会说,TCP 连接的建立与断开,这个我熟,不就是三次握手与四次挥手嘛.且慢,脑海中可以先尝试回答这几个问题: 四次挥手是谁发起的? 如果断电/断网了连接会断开吗? 什么情况下没 ...

  2. the Agiles Scrum Meeting 7

    会议时间:2020.4.15 21:00 1.每个人的工作 根据项目进度,我们将原先的完善组和debug组合并,成为团队项目增量开发组,原增量组成为个人结对项目增量开发组. 今天已完成的工作 个人结对 ...

  3. 详解DNS域名解析系统(域名、域名服务器[根、顶级、授权/权限、本地]、域名解析过程[递归与迭代])

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/105583806 学习课程:<2019王道考研计算机网络> 学习目的 ...

  4. 设计模式(1-2)-动态代理(newProxyInstance)

    上节设计模式(1-1)-代理模式,讲了代理模式的静态代理与动态代理的写法.本节,会从Proxy.newProxyInstance() 这个方法开始讲,上一节文末的那个class文件怎么一步步的来的. ...

  5. clone-graph leetcode C++

    Clone an undirected graph. Each node in the graph contains alabeland a list of itsneighbors. OJ's un ...

  6. 深入了解Mybatis架构设计

    架构设计 我们可以把Mybatis的功能架构分为三层: API接口层:提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库.接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理. ...

  7. 释放 cached 内存

    巡检服务器发现内存可用很少了 top 命令查看是没有占用大内存的进程,cached特别大,释放cached就可以了 可用内存= free + buffers + cached 以下方法可以释放cach ...

  8. 怎么将本地已有的一个项目上传到新建的git仓库的方法

    将本地已有的一个非git项目上传到新建的git仓库的方法一共有两种. 一. 克隆+拷贝 第一种方法比较简单,直接用把远程仓库拉到本地,然后再把自己本地的项目拷贝到仓库中去.然后push到远程仓库上去即 ...

  9. Vue中computed计算属性

    话不多说,使用方法直接上代码//在模板中调用computedTest这个函数,切记不要在函数后添加()<template> <div class="home"&g ...

  10. linux 入门系列-基础性知识

    1:初探linux-基于centos7 运维和服务器硬件组合 两种登录方式:(1)-------root:管理员登录权限较高,不建议初学者使用格式: [root@centos7 jinlong]# ( ...