[cf1434E]A Convex Game
暴力求SG,结论:每一个序列的SG上限为$\sqrt{2\max a_{i}}+1$
证明:将SG的转移看作一张DAG,归纳每一个点的SG值不超过其开始的最长路,显然成立
那么本题中最长路即在$a_{i}$中最多能选多少次,假设选择的权值依次为$v_{1},v_{2},...,v_{m}$,则$v_{i+1}-v_{i}\ge i$,累加即$v_{m}-v_{1}\ge \frac{m(m-1)}{2}$,放缩得$(m-1)^{2}<2v_{m}$,$m$也即SG的上限为$\sqrt{2\max a_{i}}+1$
考虑dp,令$f_{i,j}$表示最后两次分别选了$a_{i}$和$a_{j}$的SG值,转移为$f_{i,j}=mex(\{f_{k,i}|a_{k}-a_{i}>a_{i}-a_{j}\})$,利用$k$的单调性,倒序枚举$j$,可以做到$o(n^{2})$,最终答案即为$mex(\{f_{i,0}|1\le i\le n\})$
令$g_{i,j}=\min_{f_{i,k}>j}k$,根据上面的结论,$g$的总数量为$o(n\sqrt{n})$,考虑直接转移$g$
根据单调性,有$g_{i,j}\ge g_{i,j-1}$,这也就保证了$f_{i,g_{i,j}}$后面的集合包含了$[1,j)$,同时$j$也需要出现,因此即要求$\exists k,a_{g_{i,j}}>2a_{i}-a_{k}且f_{k,i}=j$,后者又等价于$g_{k,j-1}\le i<g_{k,j}$,贪心求出满足后者的$k$中最大值即可
考虑先枚举$j$,维护线段树,每一次先查询$i$上的值并判断,再令区间$[g_{i,j-1},g_{i,j})$的值对$i$取max,时间复杂度为$o(n\sqrt{n}\log_{2}n)$,略微卡常
进一步优化,由于插入的区间单调递增,因此可以看作对未被修改的部分修改,维护两个并查集,分别表示:1.上一个未被覆盖的点;2.同一种类型的上一个点,时间复杂度为$o(n\sqrt{n}\alpha(n))$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1) 7 int t,n,ans,a[N],f[2][N],fa[N],pre[N],v[N]; 8 int find(int k){ 9 if (fa[k]==k)return k; 10 return fa[k]=find(fa[k]); 11 } 12 int get_pre(int k){ 13 if (k==pre[k])return k; 14 return pre[k]=get_pre(pre[k]); 15 } 16 void update(int l,int r,int x){ 17 r=get_pre(r); 18 if (v[r])r--; 19 if (l>r)return; 20 while (1){ 21 int nex=get_pre(r-1); 22 if (v[nex])nex--; 23 if (nex<l){ 24 v[r]=x; 25 return; 26 } 27 fa[r]=nex; 28 r=nex; 29 } 30 } 31 void merge(int l,int r){ 32 if ((r<=n)&&(pre[r+1]==r+1)&&(v[r+1]))pre[r+1]=r; 33 r=get_pre(r); 34 while (l<r){ 35 pre[r]=r-1; 36 r=get_pre(r-1); 37 } 38 if ((l==r)&&(l>1)&&(v[get_pre(l-1)]))pre[r]=r-1; 39 } 40 int query(int k){ 41 return v[find(k)]; 42 } 43 int main(){ 44 scanf("%d",&t); 45 while (t--){ 46 scanf("%d",&n); 47 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 48 int s=0,p=0,flag=0; 49 for(int i=1;i<=n;i++)f[p][i]=1; 50 while (!flag){ 51 flag=1; 52 s++; 53 p^=1; 54 for(int i=1;i<=n;i++){ 55 fa[i]=pre[i]=i; 56 v[i]=0; 57 } 58 for(int i=n;i;i--){ 59 int k=query(i); 60 if(!k)f[p][i]=n+1; 61 else f[p][i]=upper_bound(a+1,a+n+1,2*a[i]-a[k])-a; 62 if (f[p^1][i]>=f[p][i])f[p][i]=f[p^1][i]; 63 else{ 64 update(f[p^1][i],f[p][i]-1,i); 65 merge(f[p^1][i],f[p][i]-1); 66 } 67 if (f[p][i]<=n)flag=0; 68 } 69 } 70 ans^=s; 71 } 72 if (ans)printf("YES"); 73 else printf("NO"); 74 }