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;
}
View Code

 

根号分治过程:

  • 弄出一个lim, 将这道题分为2个部分,分别做
  • 一般是一边是暴力,一边是更具这lim来优化时间复杂度

    想法就是: 枚举某个值时, 有些过程是否会更具这个值的变大而减少

 

posted @ 2022-10-18 10:45  VxiaohuanV  阅读(30)  评论(0编辑  收藏  举报