首页 > 其他分享 >Codeforces 1603D. Artistic Partition

Codeforces 1603D. Artistic Partition

时间:2023-06-23 21:33:38浏览次数:96  
标签:1603D Partition int sum mn Codeforces ls Artistic

题目链接:D - Artistic Partition

题目大意:要求将 \([1,n]\) 分成 \(k\) 段,使得每段对应的 \(c(l,r)\) 之和最小,其中 \(c(l,r)=\sum_{i=l}^r\sum_{j=i}^r[\gcd(i,j)\ge l]\)。

首先注意到当 \(r<2l\) 时,\(c(l,r)=r-l+1\)。所以当 \(2^k-1\ge n\) 时答案即为 \(n\)。

考虑 \(\texttt{DP}\),设 \(f_{i,j}\) 表示已经分了 \(i\) 段,段末为 \(j\) 的最小值,则转移式为 \(f_{i,j}=\min\{f_{i-1,k}+c(k+1,j)\}\)。

考虑转移过程中,每次 \(j-1\) 到 \(j\) 对每个 \(f_{i-1,k}+c(k+1,j)\) 造成的影响。需要快速维护每个 \(k\) 对应值的变化量,即 \(c(k+1,j)-c(k+1,j-1)\),显然这个值为 $\sum_{i=k+1}^{j} [\gcd(i,j)\ge k+1] $。

由于 \(i<j\) 时,\(\gcd(i,j)\le i\),于是就相当于要对每个位置 \(k\) 加上 $\sum_{i=1}^{j} [\gcd(i,j)\ge k+1] $。进一步地,其实就是加上 \(j-\sum_{i=1}^{j} [\gcd(i,j)\le k]\)。众所周知,\(\gcd(i,j)\) 的取值只可能是 \(j\) 的约数,那么把 \(j\) 的所有约数 \(d_i\) 求出来,每次将区间 \([d_{i},d_{i+1})\) 加上对应贡献即可。初始贡献为 \(j\),当 \(i\) 每次加一时贡献会减少 \(\varphi(\frac{j}{d_i})\),这是与 \(j\) 取 \(\gcd\) 的值为 \(d_i\) 的方案数。处理完每个位置的变化量后,当前的全局最小值即为 \(f_{i,j}\) 的值。

时间复杂度方面,相当于在每一层转移中,对于每对 \((j,d_i)\) 都要进行一次线段树的区间加操作,那么显然是一个 \(O(n\log^3n)\) 的复杂度。于是为了卡常,需要将这个区间加变成后缀加才可通过此题。

#include<bits/stdc++.h>
using namespace std;
#define N 100010
#define ls o<<1
#define rs o<<1|1
#define LL long long
int T,n,k,cnt,p[N],v[N],phi[N];
LL f[20][N];
vector<int>d[N];
struct rua
{
	LL tag,mn;
}t[N<<2];
void Build(int o,int l,int r,int i)
{
	t[o].tag=0;
	if(l==r){
		t[o].mn=f[i][l];
		return;
	}
	int mid=l+r>>1;
	Build(ls,l,mid,i);
	Build(rs,mid+1,r,i);
	t[o].mn=min(t[ls].mn,t[rs].mn);
}
void add(int o,int tl,int tr,int l,int r,int c)
{
	if(l<=tl && tr<=r){
		t[o].tag+=c;
		t[o].mn+=c;
		return;
	}
	int mid=tl+tr>>1;
	if(l<=mid)add(ls,tl,mid,l,r,c),t[rs].tag+=c,t[rs].mn+=c;
	else add(rs,mid+1,tr,l,r,c);
	t[o].mn=min(t[ls].mn,t[rs].mn)+t[o].tag;
}
void pretype()
{
	phi[1]=1;
	for(int i=2;i<N;i++){
		if(!v[i])p[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt && i*p[j]<N;j++){
			v[i*p[j]]=1;
			if(i%p[j]==0){
				phi[i*p[j]]=phi[i]*p[j];
				break;
			}
			phi[i*p[j]]=phi[i]*phi[p[j]];
		}
	}
	for(int i=1;i<N;i++)
	for(int j=i;j<N;j+=i)
		d[j].push_back(i);
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<N;i++)f[1][i]=1ll*i*(i+1)/2;
	for(int i=2;i<=17;i++){
		LL v=0;
		Build(1,1,N-1,i-1);
		for(int j=1;j<N;j++){
			v+=j;
			for(auto k:d[j])add(1,1,N-1,k,N-1,-phi[j/k]);
			f[i][j]=v+t[1].mn;
		}
	}
}
int main()
{
	pretype();
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&k);
		if(k>20 || (1<<k)-1>=n)printf("%d\n",n);
		else printf("%lld\n",f[k][n]);
	}
}

标签:1603D,Partition,int,sum,mn,Codeforces,ls,Artistic
From: https://www.cnblogs.com/DeaphetS/p/17499329.html

相关文章

  • Codeforces Round 766 (Div. 2) 比赛报告
    0比赛经过比赛还没开始的时候就感觉状态不太好。果然。总归到底都是一个心态问题。A题经过看A题,结果半天看不懂,一开始没有注意到一定要在黑格子上操作。扔到DeepL上翻译了一下,再手玩一下样例就做出来了,速度有点慢。CF怎么这么喜欢出分讨题啊。看题目不能太急,要一个一......
  • Codeforces Round 881 (Div. 3)--F2
    F2.OmskMetro(hardversion)#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;#defineendl"\n"#defineintlonglongconstintN=2e5+5;constintINF=0x3f3f3f3f;//假设一个区间的最大字段和为max最小字段和为min//那么[min,max]区间的......
  • Codeforces 1835F - Good Graph
    goodproblem,badround。判断YES还是NO很trivial,就直接跑最大匹配看看是不是\(n\)即可。如果是NO,那么考虑Hall定理的证明过程构造即可。具体方法就是找到左部任意一非匹配点,在残量网络上BFS可以到达的点,那所有可以到达的左部点形成的集合就是符合要求的反例。因为你......
  • Codeforces 1835E - Old Mobile
    首先先观察到一个非常浅显的性质:就是一个位置在序列中不是第一次出现,那么到这个位置的时候打出这个字符需要恰好一次按键,这是因为我们肯定在打出第一次出现这个字符的位置的时候已经知道哪个键对应这个字符了,到那个位置的时候直接敲一下就ok了。也就是我们只用关心这个序列中出......
  • Codeforces Round 878 (Div. 3) D. Wooden Toy Festival
    题目翻译:给定一个序列,你可以把序列分为任意的三组不要求顺序,对于每一组序列给出一个数字作为标准,求出序列中和该数字的差绝对值的最大值,现在要求你选顶三个数字使得三个序列的差最大值的最大值最小解题思路:二分,要想方差最小,就让每一组的极差都最小,即最大值减最小值最小#include......
  • 练习记录-cf-Codeforces Round 881 (Div. 3)A-F1
    E是补的太蠢了没想到期末考完的复健A.SashaandArrayColoring题意:可以给不同数字涂上很多颜色,每个颜色的贡献是同一个颜色内的数字最大值和最小值的差思路:排序一遍,取头和尾的差#include<bits/stdc++.h>#defineclosestd::ios::sync_with_stdio(false),cin.tie(0)......
  • CodeForces 合集
    1838E.CountSupersequenceshttps://codeforces.com/contest/1838/problem/E题意给定\(n,m,k\),一个长度为\(n\)的序列\(a=(a_1,a_2,\dots,a_n)\),满足\(1\leqa_i\leqk\),求有多少个序列\(b=(b_1,b_2,\dots,b_m)\),满足\(a\)是\(b\)的一个子序列,并且\(......
  • Codeforces Round 880 (Div. 2) C. k-th equality
    看好久题目了,题目大意是给定三个位数A,B,C和一个k,要求求所有满足要求的a+b=c等式中的第k个等式等式按字典序由小到大枚举,例如1+9=10和2+6=8中1+9=10比2+6=8小思路我们首先求出a,b,c的取值范围,然后先确定a,对于每一个确定的a都有一个确定的b和c区间与之对应,并且a+b=c,c=a-b,当a和b......
  • Educational Codeforces Round 82 (Rated for Div. 2)_A. Erasing Zeroes(C++_模拟)
    Youaregivenastring.Eachcharacteriseither0or1.Youwantall1’sinthestringtoformacontiguoussubsegment.Forexample,ifthestringis0,1,00111or01111100,thenall1’sformacontiguoussubsegment,andifthestringis0101,100001o......
  • Codeforces Round 879 (Div. 2) 题解
    寄!大!了!Rating-=124.(恼)https://codeforces.com/contest/1834C.GamewithReversing发现\(\text{rev}(S)\toS\)和\(\text{rev}(T)\toT\)本质上是一样的。赛时就一个劲的对着\(S\)操作,,,。我们考虑单点修改在\(S\)上做,翻转操作在\(T\)上做。设\(\displaysty......