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