Arithmetic Operations (根号分治)
题目大意:
给你一个 序列 an , 你可以进行操作, 将ai 变成任意一个数字, 问你将这个序列弄成等差数列,需要的最小操作次数, n为10^5, ai 1-10^5.
思路:
- 直接搞不好下手, 考虑转化题意
- ai + d*i, 有多少个这样相同的数 , 枚举D就行了, 用桶存每一个位置的数就行了
- 这是暴力做法, n*d的时间复杂度
- 继续观察,当 d 比较大时,
- 枚举每一个ai 当首项, 会发现 最多有 1e5/d 个数是合法的,因此可以对此进行优化
- 弄一个阈值作为lim,将这道题分为2个部分, 小于lim的d, 直接暴力做,
- 大于lim的值, 就最多会有1e5/lim 的数可能合法 枚举每一个ai 当首项, 在枚举 后面1e5/lim 个数, 用一个桶来存 出现的 d , 看哪一个d出现的数量是最多的

#define int long long #define B 30000000 int n,a[100010],cnt[2*B+10],ans=1e16; signed main(){ read(n); For(i,1,n) read(a[i]); For(i,-200,200){ For(j,1,n) cnt[a[j]-i*j+B]++; int mx=0; For(j,1,n) ckmax(mx,cnt[a[j]-i*j+B]); For(j,1,n) cnt[a[j]-i*j+B]=0; ckmin(ans,n-mx); } For(i,1,n){ For(j,i+1,min(n,i+500)) if((a[j]-a[i])%(j-i)==0) cnt[(a[j]-a[i])/(j-i)+B]++; int mx=0; For(j,i+1,min(n,i+500)) if((a[j]-a[i])%(j-i)==0) ckmax(mx,cnt[(a[j]-a[i])/(j-i)+B]); For(j,i+1,min(n,i+500)) if((a[j]-a[i])%(j-i)==0) cnt[(a[j]-a[i])/(j-i)+B]=0; ckmin(ans,n-mx-1); } cout<<ans<<endl; }
根号分治过程:
- 弄出一个lim, 将这道题分为2个部分,分别做
- 一般是一边是暴力,一边是更具这lim来优化时间复杂度
想法就是: 枚举某个值时, 有些过程是否会更具这个值的变大而减少