Artistic Partition

题解

看到这种统计最小值的题应该很容易想到 d p dp dp,我们可以记 d p i , j dp_{i,j} dpi,j​表示划分到点 i i i,已经划分了 j j j块,但如果直接进行 d p dp dp转移的话显然会 T T T。
但我们可以猜测到一点,当 K K K比较大的时候,我们应该很容易划分这个序列使得每个数在其区间中,与除自己外的所有数的 gcd ⁡ \gcd gcd都不大于改区间的 l l l。
也就是说我的的答案就为 n n n。
有了这个结论,我们就可以去想想怎么划分。
一个区间 [ l , r ] [l,r] [l,r]第一个会使得 gcd ⁡ ( l , r ) ⩾ l \gcd(l,r)\geqslant l gcd(l,r)⩾l的数对显然是 ( l , 2 l ) (l,2l) (l,2l),也就是说,如果我们的 r < 2 l r< 2l r<2l,改区间答案便为 r − l + 1 r-l+1 r−l+1。
容易发现,这样的话,只要我们的 2 k > n 2^k>n 2k>n,就答案就为 n n n。也就是说,我们需要 d p dp dp的 K K K是 log ⁡ n \log n logn级别的,我们的总状态数是 n log ⁡ n n\log n nlogn级别。

我们的状态数大概无法继续优化了,但我们的 d p dp dp转移是可继续优化的。
我们用 c ( l , r ) c(l,r) c(l,r)表示将区间 [ l , r ] [l,r] [l,r]划分一段所产生的贡献,则转移式为:
d p i , k = min ⁡ j = 0 i − 1 ( d p j , k − 1 + c ( j + 1 , i ) ) dp_{i,k}=\min_{j=0}^{i-1}\left(dp_{j,k-1}+c(j+1,i)\right) dpi,k​=j=0mini−1​(dpj,k−1​+c(j+1,i))显然,这个 d p dp dp转移是单调的,对于 k k k相同的 d p dp dp,显然我 i i i越大,我们的划分点就会继续右移。
事实上,我们可以通过说明对于 l < l ′ < r ′ < r l<l'<r'<r l<l′<r′<r,有 c ( l , r ) + c ( l ′ , r ′ ) ⩾ c ( l , r ′ ) + c ( l ′ , r ) c(l,r)+c(l',r')\geqslant c(l,r')+c(l',r) c(l,r)+c(l′,r′)⩾c(l,r′)+c(l′,r)来证明它的单调性。
而这个式子显然是成立的,前面的部分比后面多了区间 [ l , l ′ ) [l,l') [l,l′)与区间 ( r ′ , r ] (r',r] (r′,r]间的贡献。
这样的话,我们就可以用分治优化我们的 d p dp dp转移了。

但无论怎么转移,我们都需要快速求出我们的 c ( l , r ) c(l,r) c(l,r)呀。
推一推 c c c的式子。
c ( l , r ) = ∑ i = l r ∑ j = i r [ ( i , j ) ⩾ l ] = ∑ d = l r ∑ i = l r ∑ j = i r [ ( i , j ) = d ] = ∑ d = l r ∑ i = 1 ⌊ r d ⌋ ∑ j = 1 i [ ( i , j ) = 1 ] = ∑ d = l r ∑ i = 1 ⌊ r d ⌋ φ ( i ) = ∑ d = l r s ( r d ) c(l,r)=\sum_{i=l}^{r}\sum_{j=i}^{r}[(i,j)\geqslant l]=\sum_{d=l}^{r}\sum_{i=l}^{r}\sum_{j=i}^{r}[(i,j)=d]\\ =\sum_{d=l}^{r}\sum_{i=1}^{\lfloor\frac{r}{d}\rfloor}\sum_{j=1}^{i}[(i,j)=1]=\sum_{d=l}^{r}\sum_{i=1}^{\lfloor\frac{r}{d}\rfloor}\varphi(i)=\sum_{d=l}^{r}s(\frac{r}{d}) c(l,r)=i=l∑r​j=i∑r​[(i,j)⩾l]=d=l∑r​i=l∑r​j=i∑r​[(i,j)=d]=d=l∑r​i=1∑⌊dr​⌋​j=1∑i​[(i,j)=1]=d=l∑r​i=1∑⌊dr​⌋​φ(i)=d=l∑r​s(dr​)其中 s ( n ) = ∑ i = 1 n φ ( i ) s(n)=\sum_{i=1}^n\varphi(i) s(n)=∑i=1n​φ(i),也就是 φ \varphi φ的前缀和。
而这就可以整除分块了,我们可以先预处理一下块的前缀和,每次查询就算一下它所在块后缀和,再加上整块的后缀和就行了。
这样就可以做到预处理 O ( n n ) O\left(n\sqrt n\right) O(nn ​),单次查询 O ( 1 ) O\left(1\right) O(1)。
事实上我们可以再将整个 d p dp dp数组都预处理了,然后每次询问就可以 O ( 1 ) O\left(1\right) O(1)回答了。

总时间复杂度 O ( n log ⁡ 2 n + n n ) O\left(n\log^2 n+n\sqrt n\right) O(nlog2n+nn ​)。

源码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
typedef long double Ld;
typedef pair<LL,LL> pii;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int mod=1e6+7;
const int inv2=499122177;
const int inv3=332748118;
const int jzm=2333;
const int zero=2000;
const int n1=100;
const int lim=100000;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double feps=1e-11;
const double eps=1e-9;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
template<typename _T>
void print(_T x){if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int T,n,K,prime[MAXN],cntp,phi[MAXN];
LL pre[MAXN],dp[MAXN][20],mp1[MAXN][405],mp2[MAXN][405];
int al[MAXN],ar[MAXN],idx;
bool oula[MAXN];
void init(){pre[1]=1;for(int i=2;i<=n;i++){if(!oula[i])prime[++cntp]=i,phi[i]=i-1;for(int j=1;j<=cntp&&i*prime[j]<=n;j++){oula[i*prime[j]]=1;if(i%prime[j]==0){phi[i*prime[j]]=prime[j]*phi[i];continue;}else phi[i*prime[j]]=(prime[j]-1)*phi[i];}pre[i]=pre[i-1]+phi[i];}for(int i=1;i<=n;i++){idx=0;LL summ=0;for(int l=1,r;l<=i;l=r+1)r=i/(i/l),idx++,al[idx]=l,ar[idx]=r;for(int j=idx;j>0;j--){summ+=1ll*(ar[j]-al[j]+1)*pre[i/ar[j]];if(al[j]<=i/al[j])mp1[i][al[j]]=summ;else mp2[i][i/al[j]]=summ;}}
}
LL work(int L,int R){if(L>R)return 0;int r=R/(R/L)+1;return 1ll*(r-L)*pre[R/L]+(r<=R/r?mp1[R][r]:mp2[R][R/r]);
}
void sakura(int l,int r,int L,int R,int k){int mid=l+r>>1;dp[mid][k]=INF;LL tmp=work(R+1,mid);int mk=0;for(int i=min(mid,R);i>=L;i--){if(dp[i][k-1]+tmp<dp[mid][k])dp[mid][k]=dp[i][k-1]+tmp,mk=i;if(i&&i<=mid)tmp+=pre[mid/i];}if(l<mid)sakura(l,mid-1,L,mk,k);if(r>mid)sakura(mid+1,r,mk,R,k);
}
int main(){read(T);n=100000;K=16;init();dp[0][0]=0;for(int i=1;i<=n;i++)dp[i][0]=INF;for(int i=1;i<=K;i++)sakura(0,n,0,n,i);while(T--){read(n);read(K);if(K>16||(1<<K)-1>=n){printf("%d\n",n);continue;}printf("%lld\n",dp[n][K]);}return 0;
}

谢谢!!!

[CF1603D]Artistic Partition相关推荐

  1. [CF1603D] Artistic Partition——欧拉函数,线段树优化DP

    [CF1603D] Artistic Partition 题解 问题其实就是要你把 1 ∼ n 1\sim n 1∼n 分成 k k k 段,最小化每一段的 c c c 值的和. 首先我们会想到,如果 ...

  2. [CodeForces1603D] Artistic Partition(四边形不等式 + 决策单调性优化dp + 分治 + 线性筛 + 数论分块)

    problem codeforces 对于给定的正整数 l≤l\leql≤,定义 c(l,r)c(l,r)c(l,r) 为满足下列条件的正整数对 (i,j)(i,j)(i,j) 的数量: l≤i≤j≤ ...

  3. [CareerCup] 2.4 Partition List 划分链表

    2.4 Write code to partition a linked list around a value x, such that all nodes less than x come bef ...

  4. min聚合函数查询带有额外字段sql|dense_rank()over(partition)|+班级学生成绩最高

    oracle爱好者和群snowg的问题 上面的这个,有站点stationid,year,month,day和每天记录的day_tmin字段. 现在要求统计处每个stationid下面每月每日的最小da ...

  5. 使用ROW_NUMBER 和partition by 解决报表中的查询问题

    在报表中遇到一个查询问题: 原始数据如下: Id cust_id call_date call_result 1 1 2012-03-15 09:00:00 fail 2 1 2012-03-15 0 ...

  6. D - Triangle Partition HDU - 6300 sort(cmp)

    D - Triangle Partition HDU - 6300 题解 由于三点不共线,且三角形不相交,则对坐标排序,输出 #include<bits/stdc++.h> using n ...

  7. mysql col与row_使用mysql实现row_number() over(partition by col1 order by col2)函数

    [color=red]row_number() OVER (PARTITION BY COL1 ORDER BY COL2)[/color] 表示根据COL1分组,在分组内部根据 COL2排序,而此函 ...

  8. A Learned Representation for Artistic Style论文理解

    A Learned Representation for Artistic Style论文理解 这篇论文是在Perceptual losses for real-time style transfer ...

  9. Leetcode PHP题解--D14 561. Array Partition I

    561. Array Partition I 题目链接 561. Array Partition I 题目分析 本题给了一个数组,要求将数组分为n个只有2个元素的一对. 使得每对数字中最小的数加起来的 ...

最新文章

  1. HDU - 5874 Friends and Enemies 完全二分图
  2. 在请求完成后回调delegate的方法。然而回调时经常遇到这种情况:delegate已经被释放...
  3. 文件得编码和文件名的编码是不一样的
  4. 计算机内页动画的作用是什么,滑环工作原理动画示意图有什么作用?
  5. oracle的数据泵导入,导出以及创建用户及删除当前连接用户
  6. opencv生成灰度图并保存
  7. 按键精灵定位坐标循环_[按键精灵教程]带你了解多点找色、多点比色
  8. Unity Shader Alpha测试
  9. QGIS二次开发01---临时绘制图层实现
  10. js模仿QQ头像资料卡显示与隐藏
  11. VCC和GND短路,怎么找问题?
  12. win32-c语言实现俄罗斯方块
  13. 实时换脸技术——直播,视频通话|脸部交换程序
  14. XML Shema 笔记整理(1)
  15. Android PowerManager 进入屏保、睡眠的过程梳理
  16. 保存相片是什么图像格式?
  17. HTTP协议状态及报文组成 - 一文通读
  18. 动态代理及JDK动态代理源码分析
  19. 未来已来——云应用引擎CAE开启应用Serverless新时代
  20. 安卓编程常见错误记录

热门文章

  1. 透视裁剪工具将倾斜的图片调正
  2. 压缩图片大小怎么弄?这样压缩不改变清晰度
  3. 微信公号开发之图文消息全攻略
  4. 电脑故障排除方法(风扇转一下,马上就停,主板没有其它任何响应)
  5. 双击打开Excel文件要反应很久之后才能打开,先开excel程序,再打开文件就很快的解决办法...
  6. 2021-2027中国超声成像检查台市场现状及未来发展趋势
  7. 数据结构与算法基础学习(一)
  8. shell for循环命令行_七年老运维实战中的 Shell 开发经验总结
  9. 魔域服务器修改和宝宝数据,宝宝属性与真实值之间的公式计算关系
  10. Matlab代码模板,图像处理,色彩补偿,色彩平衡,显示连通分量数量