1. 程式人生 > 其它 >題解 CF1654E Arithmetic Operations

題解 CF1654E Arithmetic Operations

容易發現,題意可以轉化為:對於所有公差 \(k\),把序列第 \(i\) 個數修改為 \(a_i-i\times k\),最多有多少個相等的數。

\(|k|\ge 10^5\) 時,必然不可能相等。因此只要考慮 \(-10^5<k<10^5\) 的情況。

考慮兩個數距離為 \(dis\) 時,只有 \(dis\times |k|\le 10^5\) 才可能相等。因此,當 \(k\) 比較大的時候,每個數只可能和它後(前)面的 \(\lfloor \dfrac{n}{k}\rfloor\) 個數相等。且如果 \(i\) 位置與 \(j\) 位置相等,\(k\) 是可以唯一確定的。

根號分治即可。取閾值為 \(lim\)

,第一部分暴力列舉公差 \(O(lim\times n)\),第二部分列舉第一個相等的數以及它後面 \(\lfloor \dfrac{n}{k}\rfloor\) 個數,複雜度 \(O(\dfrac{n^2}{lim}\))。所以當 \(lim=\sqrt{n}\),複雜度是 \(O(n\sqrt{n})\)。需要開 \(O(n\sqrt{n})\) 大小的桶記錄。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(x) memset(x,0,sizeof(x))
#define printYes puts("Yes")
#define printYES puts("YES")
#define printNo puts("No")
#define printNO puts("NO")
#define lowbit(x) (x&(-x))

const ll inf=1000000000000000000; 
//const ll mod=998244353;
//const ll mod=1000000007;

const int N=100005,B=321,K=N*B+2*N;
int n,m,ans; 
int a[N];

int b[N*B*2+4*N],c[N];

inline int read()
{
    int F=1,ANS=0;
	char C=getchar();
    while (C<'0'||C>'9')
	{
		if (C=='-') F=-1;
		C=getchar();
	}
    while (C>='0'&&C<='9')
	{
		ANS=ANS*10+C-'0';
		C=getchar();
	}
    return F*ANS;
}

int main()
{
	n=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=-B;i<=B;i++)
	{
		for (int j=1;j<=n;j++)
		{
			b[a[j]-i*j+K]++;
			ans=max(ans,b[a[j]-i*j+K]);
		}
		for (int j=1;j<=n;j++)
		{
			b[a[j]-i*j+K]--;
		}
	}
	for (int i=1;i<=n;i++)
	{
		int r=min(n,i+B);
		for (int j=i+1;j<=r;j++)
		{
			int det=a[j]-a[i],len=j-i;
			if (det%len!=0) continue;
			int k=det/len;
			b[k+K]++;
			ans=max(ans,b[k+K]+1);
		}
		for (int j=i+1;j<=r;j++)
		{
			int det=a[j]-a[i],len=j-i;
			if (det%len!=0) continue;
			int k=det/len;
			b[k+K]--;
		}
	}
	cout << n-ans;
	return 0;
}