P10885 【MX-S3-T1】「FeOI Round 1」野心
思路
在一个排序后为等差数列的数列中,定义
试分析以
先定义
存在如下
-
当
l \in [1,2] 时,d \in [1,n-1] 。 -
当
l \in [3,n] 时,d=\begin{cases} 1\ 或\ 2& l\ 为“特殊的”,\\ 1 & \mathop{\operatorname{otherwise}}.\\ \end{cases}
再定义
注意到,
下面以求出
正难则反,我们设出
显然,
当
-
先设
d=1 。若l=\mathop{\operatorname{max}}(p_1,p_2,\cdots,p_i)-\mathop{\operatorname{min}}(p_1,p_2,\cdots,p_i)+1 ,则d 合法。 -
若
l 为“特殊的”,再设d=2 ,此时遍历数列[p_1,p_2,\cdots,p_i] 判断d 的合法性(详情见代码)。
不难发现,求 不会爆时间。
求
代码
#include<bits/stdc++.h>
#define int long long
#define INF 0x7fffffffffffffff
#define _max(a,b) ((a)>(b)?(a):(b))
#define _min(a,b) ((a)<(b)?(a):(b))
#define maxn 2000010
using namespace std;
int t,n,a[maxn],vis[maxn],f[maxn],g[maxn],ans;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')ret=ret*10+(ch&15),ch=getchar();
return ret*f;
}
signed main(){
t=read();
while(t--){
n=read(),ans=0;
for(int i=1;i<=n;i++)a[i]=read(),vis[i]=0;
if(n==1){printf("0\n");continue;}
//求 f[i]
int cnt=0,minn=INF,mx=-INF;
for(int i=1;i<=n;i++){
vis[a[i]]=1;
if(a[i]>=mx)mx=a[i];
if(a[i]<=minn)minn=a[i];
if(mx-minn+1==i||i<=2){f[i]=1;continue;}
if(((n&1)&&(i==(n>>1)||i==(n>>1)+1))||(!(n&1)&&(i==(n>>1)))){
int k=((mx-minn)>>1)+1;
if(k!=i){f[i]=0;continue;}
int op=0;
for(int j=minn;j<=mx;j+=2)if(!vis[j]){op=1;break;}
f[i]=op^1;
}else f[i]=0;
}
//求 g[i]
cnt=0,minn=INF,mx=-INF;
for(int i=1;i<=n;i++)vis[i]=0;
for(int i=n;i>=1;i--){
vis[a[i]]=1;
if(a[i]>=mx)mx=a[i];
if(a[i]<=minn)minn=a[i];
if(mx-minn+1==(n-i+1)||(n-i+1)<=2){g[i]=1;continue;}
if(((n&1)&&((n-i+1)==(n>>1)||(n-i+1)==(n>>1)+1))||(!(n&1)&&(n-i+1)==(n>>1))){
int k=((mx-minn)>>1)+1;
if(k!=(n-i+1)){g[i]=0;continue;}
int op=0;
for(int j=minn;j<=mx;j+=2)if(!vis[j]){op=1;break;}
g[i]=op^1;
}else g[i]=0;
}
for(int i=1;i<=n-1;i++)if(f[i]&&g[i+1])ans++;
printf("%lld\n",ans);
}
return 0;
}