codeforces#Round778-E. Arithmetic Operations

E. Arithmetic Operations(分类+思维)

题意

给你一个数组\(a\),每次操作可以选择一个\(a_i\) ,将其变成任意一个数\(x\),问你最少操作多少次使之变成一个等差数列。

思路

之前cf有过等差数列这类题目,当时是求修改量的和最少,而我们现在则是求修改次数最少。当时第一个思路就是枚举d,然后通过\(a_i-i*d\)找最长的数值相等的序列。但是2e5的d劝退了我。

其实这时候我们可以将d分为两类,0<d<=sqrt(m),和d>sqrt(m),至于负数的部分,反转数组再进行该操作即可。

这样分的好处就是对于d<=sqrt(m)这个部分,可以直接用我上面的思路来完成。而>sqrt(m)的这个部分,我们可以发现,当公差为d时,而一个数的最大值才是m,那么对于该种情况下的d,最多只能容纳sqrt(m)个数的数,后面的数也不用一直暴力下去了

1.d<=sqrt(m)

枚举公差\(d\),对于每一个\(d\),我们让\(a_i-i*d\),相当于把偏移量减去,剩下的最多的就是我们要留下数

2.d>sqrt(m)

枚举每个起始点,每次最多找sqrt(m)个数,在这其中找存在的d存入数组,然后排序完后暴力寻找最多的d,假设数量为\(maxx\),说明存在\(maxx+1\)个数

代码

#include<iostream>
#include<cstring>
#include<stack>
#include<queue>
#include<stdio.h>
#include<string>
#include<string.h>
#include <map>
#include<cstdio>
#include<set>
#include<stdlib.h>
#include<algorithm>
#include <math.h>
#include<cmath>
#include<list>
#include<time.h>
#include<set>
#include<vector>
#include<iomanip>
#include<fstream>
#include<cstdlib>
#include<sstream>
#include <random>
#include <functional>
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 7;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-8;
const double eps2 = 1e-2;
const ll mod = 998244353;
const double gold = (sqrt(5.0) - 1) / 2;
#define fast ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define edl(i,n) (i==n?'\n':' ')
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define scd(x) scanf("%lf",&x)
//#define int long long 
//#define endl "\n"
int gcd(int a, int b);
int lca(int a, int b);
int qpow(int a, int n);
int qmul(int a, int b);
// d::mt19937 rng((int)std::chrono::steady_clock::now().time_since_epoch().count());

int a[maxn];
int mp[maxn];
int n;
int maxa = 0;
int sq=350;
int solve() {
    int ans = inf;
    //<sqrt(m)

    for (int d = 0; d <= sq; d++) {
        //map<int, int>mp;
        int cnt = 0;
        int maxx = 0;
        for (int i = 1; i <= n; i++) {
            int x = a[i] - d * i;
            mp[i] = x;
            /*if (mp.count(x)) {
                mp[x]++;
            }
            else {
                mp[x] = 1;
            }*/
        }
        sort(mp+1, mp+n+1);
        cnt = n;
        int now = 1;
        for (int i = 1; i <= cnt-1; i++) {
            if (mp[i] != mp[i + 1]) {
                maxx = max(maxx, now);
                now = 1;
            }
            else {
                now++;
            }
        }
        maxx = max(maxx, now);
       /* for (auto i : mp) {
            maxx = max(maxx, i.second);
        }*/
        ans = min(ans, n - maxx);
    }
    //>=sqrt(m)
    for (int i = 1; i <= n; i++) {
        int cnt = 0;
        int maxx = 0;
        for (int j = i + 1; j <= i + sq && j <= n; j++) {
            if ((a[j] - a[i]) % (j - i) == 0) {
                int x = (a[j] - a[i]) / (j - i);
                mp[++cnt] = x;
                /*if (mp.count(x)) {
                    mp[x]++;
                }
                else {
                    mp[x] = 1;
                }*/
            }
        }
        sort(mp+1, mp+cnt+1);
        int now = 1;
        for (int i = 1; i < cnt; i++) {
            if (mp[i] !=mp[i + 1]) {
                maxx = max(now, maxx);
                now = 1;
            }
            else {
                now++;
            }
        }
        maxx = max(now, maxx);
        //for (auto i : mp) {
        //    maxx = max(maxx, i.second);
        //}
        ans = min(ans, n - maxx - 1);
    }
    return ans;
}
void resolve() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        maxa = max(a[i], maxa);
    }
    if (n == 1) {
        cout << 0 << endl;
        return;
    }
    //sq = sqrt(maxa) + 1;
    int ans = solve();
    reverse(a + 1, a + n + 1);
    ans = min(ans, solve());
    cout << ans << endl;

}

signed main() {
    fast;
    int _ = 1;
    //cin >> _;
    //sci(_);
    // rand (time(NULL));
    while (_--) {
        resolve();
    }
}

int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
}
int lca(int a, int b) {
    return a * b / gcd(a, b);
}
int qpow(int a, int n) {
    int ans = 1;
    while (n) {
        if (n & 1)
            ans = ans * a;
        a = a * a;
        n >>= 1;
    }
    return ans;
}
int qmul(int a, int b) {
    ll ans = 0;
    while (b > 0) {
        if (b & 1) ans = (ans + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return ans;
}
posted @ 2022-03-22 09:24  Hxin-C  阅读(186)  评论(0)    收藏  举报