2019ICPC EC-FINAL H-King 随机

2019ICPC EC-FINAL H-King

题意

给一个长度为(n)的数组(b),从中找到一个长度大于等于(lceil frac{n}{2} ceil)的子序列(a),存在一个(q)使得(a)中任意的下标(i)满足(a_{i-1}*q equiv a_i (mod~p))

(nle 2cdot 10^5,p le 10^9+7)

分析

(n)个数中选出(frac{n}{2})个数,两个相邻的数的在原数组中最小距离最大为2,并且会有很多相邻的数的距离小于等于2,所以我们从(1sim n)中随机一个数(x),枚举(x+1,x+2)作为和它相邻的数,计算出(q),然后前后各贪心扫一下,找到最长的等比数列,取最大值,最后和(lceil frac{n}{2} ceil)比较一下即可。

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<=n;++i)
#define per(i,n,a) for (int i=n;i>=a;--i)
#define sz(x) ((int)(x).size())
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
typedef pair<int,int> pii;
#define ll long long
const int inf=1e9;
const int mod=1e9+7;
const int N=2e5+10;
int T;
int n,p;
int b[N];
bool vis[N];
std::mt19937 rnd(time(0));
int ksm(int a,int b,int mod){
	int ret=1;
	while(b){
		if(b&1) ret=1ll*ret*a%mod;
		a=1ll*a*a%mod;
		b>>=1;
	}
	return ret;
}
int solve(int x,int y){
	int q=1ll*b[y]*ksm(b[x],p-2,p)%p;
	int pre=1ll*b[y]*q%p;
	int ans=2;
	for(int i=y+1;i<=n;i++){
		if(b[i]==pre){
			++ans;
			pre=1ll*b[i]*q%p;
		}
	}
	q=ksm(q,p-2,p);
	int last=1ll*b[x]*q%p;
	for(int i=x-1;i>=1;i--){
		if(b[i]==last){
			++ans;
			last=1ll*b[i]*q%p;
		}
	}
	return ans;
}
int main(){
	//ios::sync_with_stdio(false);
	//freopen("in","r",stdin);
	scanf("%d",&T);
	while(T--){
		memset(vis,0,sizeof(vis));
		scanf("%d%d",&n,&p);
		rep(i,1,n){
			scanf("%d",&b[i]);
		}
		int ans=2;
		for(int i=1;i<=min(n,200);i++){
			int x=rnd()%n+1;
			while(vis[x]){
				x=rnd()%n+1;
			}
			vis[x]=1;
			for(int j=x+1;j<=n&&j<=x+2;j++) ans=max(ans,solve(x,j));
		}
		if(ans>=(n+1)/2) printf("%d
",ans);
		else puts("-1");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/xyq0220/p/13775505.html