As we all know, the number of Pang’s papers follows exponential growth. Therefore, we are curious about King sequence.
You are given a prime p. A sequence (a1,a2,…,an) is a King sequence if and only if there is an integer 1≤q
Given a sequence B=(b1,…,bm), what is the length of the longest King subsequence of B?
A subsequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements.
Pang is super busy recently, so the only thing he wants to know is whether the answer is greater than or equal to n2.
If the length of the longest King sequence is less than n2, output −1. Otherwise, output the length of the longest King subsequence.
Input
The first line contains an integer T denoting the number of test cases (1≤T≤1000).
The first line in a test case contains two integers n and p (2≤n≤200000, 2≤p≤1000000007, p is a prime). The sum of n over all test cases does not exceed 200000.
The second line in a test case contains a sequence b1,…,bn (1≤bi
Output
For each test case, output one line containing the answer which is −1 or the length of the longest King subsequence.
Example
inputCopy
4
6 1000000007
1 1 2 4 8 16
6 1000000007
597337906 816043578 617563954 668607211 89163513 464203601
5 1000000007
2 4 5 6 8
5 1000000007
2 4 5 6 7
outputCopy
5
-1
3
-1
因为我们要找是否存在长度大于 n/2 ,所以我们随机选择两个数字,这两个数字出现在答案序列中的概率至少为 1/4 ,如果我们选择多次,那么答案的正确性为:1 - (3/4)^x,当x比较大的时候是可以保证正确率的。
但是现在选择的两个数字可能差距了几个公比,怎么办呢?我随机两个相邻的数字即可。什么意思呢?就是我们令当前随机出来的两个数字是答案中相邻的数字,可以证明最小的距离最大值是不会超过2的,所以直接判断x,x+1和x,x+2即可,都判断一次。
codeforces上面AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=2e5+10;
std::mt19937 rnd(time(0));
int T,a[N],n,p,dp[N],res;
unordered_map<int,int> mp;
inline int qmi(int a,int b=p-2){
int res=1;
while(b){if(b&1) res=res*1LL*a%p; a=a*1LL*a%p; b>>=1;}
return res;
}
inline int solve(int l,int r){
int res=1;
int q=a[r]*1LL*qmi(a[l])%p,inv=qmi(q); mp.clear(); dp[1]=1; mp[a[1]]=1;
for(int i=2,pre;i<=n;i++){
pre=a[i]*1LL*inv%p; dp[i]=mp[pre]+1;
mp[a[i]]=max(mp[a[i]],dp[i]); res=max(res,dp[i]);
}
return res;
}
signed main(){
ios::sync_with_stdio(false); cin.tie(nullptr);
cin>>T;
while(T--){
cin>>n>>p; res=0;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=17;i++){
int x=rnd()%(n-1)+1;
for(int j=x+1;j<=n&&j<=x+2;j++) res=max(res,solve(x,j));
}
if(res*2<n) cout<<-1<<'\n';
else cout<<res<<'\n';
}
return 0;
}
牛客时间卡得很紧,只给了1s,所以我们不用大常数unordered_map,我们直接分别前后扫一遍即可。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
#define int long long
using namespace std;
const int N=2e5+10;
std::mt19937 rnd(time(0));
int T,a[N],n,p,dp[N],res;
unordered_map<int,int> mp;
inline int qmi(int a,int b=p-2){
int res=1;
while(b){if(b&1) res=res*a%p; a=a*a%p; b>>=1;}
return res;
}
inline int solve(int l,int r){
int res=2;
int q=a[r]*qmi(a[l])%p,inv=qmi(q);
for(int i=r+1,pre=a[r];i<=n;i++) if(pre*q%p==a[i]) pre=a[i],res++;
for(int i=l-1,pre=a[l];i>=1;i--) if(a[i]*q%p==pre) pre=a[i],res++;
return res;
}
signed main(){
ios::sync_with_stdio(false); cin.tie(nullptr);
cin>>T;
while(T--){
cin>>n>>p; res=0;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=150;i++){
int x=rnd()%(n-1)+1;
for(int j=x+1;j<=n&&j<=x+2;j++) res=max(res,solve(x,j));
}
if(res<(n+1)/2) cout<<-1<<'\n';
else cout<<res<<'\n';
}
return 0;
}