[ARC126C]Maximize GCD
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ARC126C]Maximize GCD相关的知识,希望对你有一定的参考价值。
Maximize GCD
题解
首先,如果我们可以直接将所有数都补得比最大的数大,那肯定就会让它们全部相等,求出这个最大值即可。
否则,我们一定会找到
[
1
,
m
a
x
x
]
[1,maxx]
[1,maxx]中的一个数,将所有数都补成这个数的倍数。
首先如果我们观察每个数的余数变化规律,我们很容易come up with一个数论分块的做法。
很明显,这个对于
⌊
x
i
⌋
\\lfloor\\frac{x}{i}\\rfloor
⌊ix⌋相同的
i
i
i,它们的余数是可以差分的,差分值也可以差分。
所以我们很容易通过这种方法求出每一个数作为我们目标的
g
c
d
gcd
gcd时的答案。
但这种方法是
O
(
n
n
)
O\\left(n\\sqrt{n}\\right)
O(nn),根本过不了。然而我比赛时还在那卡了半天
既然横着不行,我们考虑竖着来,对每个
i
i
i求每个
A
j
A_{j}
Aj的贡献。
很明显,这贡献的变化也是有规律可循的。
它是
i
,
i
−
1
,
i
−
2
,
i
−
3
,
i
−
4
,
.
.
0
i,i-1,i-2,i-3,i-4,..0
i,i−1,i−2,i−3,i−4,..0的循环,所以我们可以考虑通过前缀和的方法求出答案。
我们单独记录下每个
x
x
x在序列中的出现次数,再记录下前缀的
s
u
m
i
=
∑
i
=
1
n
i
×
c
n
t
i
sum_{i}=\\sum_{i=1}^{n} i\\times cnt_{i}
sumi=∑i=1ni×cnti。
对于值域为
[
i
d
+
1
,
(
i
+
1
)
d
]
[id+1,(i+1)d]
[id+1,(i+1)d]区间内的数的贡献,显然是
(
s
i
z
(
i
+
1
)
d
−
s
i
z
i
d
)
(
i
+
1
)
d
−
(
s
u
m
i
+
1
d
−
s
u
m
i
d
)
(siz_{(i+1)d}-siz_{id})(i+1)d-(sum_{i+1}d-sum_{id})
(siz(i+1)d−sizid)(i+1)d−(sumi+1d−sumid),可以直接一次求出。
显然,对于
d
d
d我们需要询问
⌈
A
d
⌉
\\lceil\\frac{A}{d}\\rceil
⌈dA⌉个区间。
时间复杂度显然为
O
(
n
+
A
ln
A
)
O\\left(n+A\\ln A\\right)
O(n+AlnA)。
源码
注意最后一个区间可能会枚出 3 × 1 0 5 3\\times 10^5 3×105的范围。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 600005
#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;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int lim=1e9;
const int n1=400;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
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){x=(~x)+1;putchar('-');}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&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,cnt[MAXN];LL K,a[MAXN],ans,sum[MAXN],sum1[MAXN];
signed main(){
read(n);read(K);LL maxx=0,summ=0;
for(int i=1;i<=n;i++)read(a[i]),maxx=max(a[i],maxx),cnt[a[i]]++;
for(int i=1;i<=n;i++)summ+=maxx-a[i];int tim=0;LL now=0;
if(summ<=K){printf("%lld\\n",maxx+(K-summ)/n);return 0;}
for(int i=1;i<=600000;i++)sum[i]=sum[i-1]+1ll*cnt[i],sum1[i]=sum1[i-1]+1ll*i*cnt[i];
for(int i=1;i<=maxx;i++){
summ=0;
for(int j=i;j<=600000;j+=i){
summ-=sum1[j]-sum1[j-i],
summ+=1ll*j*(sum[j]-sum[j-i]);
}
if(summ<=K)ans=1ll*i;
}
printf("%lld\\n",ans);
return 0;
}
谢谢!!!
以上是关于[ARC126C]Maximize GCD的主要内容,如果未能解决你的问题,请参考以下文章
即使在 ARC 下,在 GCD 中使用 Realm 时,我们是不是必须使用显式自动释放池