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

浙公网安备 33010602011771号