题解:P17725 [SCP-S 2026] 大雨 / rain
首先根据异或的性质,我们发现这个题是给序列划分若干个区间,然后每个区间异或同一个值,要求区间内有序,区间断点处有序。
然后我们考虑会异或最后一段,那么我们可以给第
这个的限制是简单的,我们去找满足
这一部分时间复杂度
然后我们发现可能最后一段不操作,这样可能使答案减小一,但值域有了限制,考虑 dp。
设
然后其实数组中大量的数是无意义的,我们只关心
然后状态没啥可优化的了,考虑优化转移。
考虑去刻画转移过程,用 trie 维护能供转移的
首先,在断点处,往 trie 里加入所有满足
然后中间会产生新限制,及删掉第
最后,需要查询 trie 里最小的
第一个操作我们发现可以通过打 tag 延迟建新点的方式做到,第二个操作可以通过维护全局时间戳来做到,最后一个就是基本功了。
总时间复杂度
AC Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define uni unsigned int
#define ull unsigned long long
#define lll __int128
#define ld long double
#define pb push_back
#define mk make_pair
#define ppcnt __builtin_popcount
#define clz __builtin_clzll
const int inf=1<<30;
ll read()
{
ll k=0,f=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
while(c>='0'&&c<='9')k=k*10+c-'0',c=getchar();
return f?-k:k;
}
void write(string s){for(char c:s)putchar(c);}
int St[100],Top;
void write(int x)
{
if(x==0){putchar('0');return;}
if(x<0)putchar('-'),x=-x;
Top=0;while(x)St[++Top]=x%10,x/=10;
while(Top)putchar('0'+St[Top--]);
}
void write(ll x)
{
if(x==0){putchar('0');return;}
if(x<0)putchar('-'),x=-x;
Top=0;while(x)St[++Top]=x%10,x/=10;
while(Top)putchar('0'+St[Top--]);
}
int n,a[1000010];
int l[1000010],r[1000010],dp[1000010],b[50];
int highbit(ll x){return 63-clz(x);}
namespace Trie
{
struct Node
{
int son[2],tag;
}t[100000010];
int cnt=0,bin[100000010],top=0;
int tim[50][2],pre[50];
int newnode()
{
int p=top?bin[top--]:++cnt;
t[p].tag=-2;
t[p].son[0]=t[p].son[1]=0;
return p;
}
void del(int p)
{
if(!p)return;
del(t[p].son[0]),del(t[p].son[1]);
t[p].son[0]=t[p].son[1]=0;
bin[++top]=p;
}
void assign(int p,int ti)
{
t[p].tag=ti;
del(t[p].son[0]),del(t[p].son[1]);
t[p].son[0]=t[p].son[1]=0;
}
void pushdown(int p)
{
del(t[p].son[0]);
t[p].son[0]=newnode();
t[t[p].son[0]].tag=t[p].tag;
del(t[p].son[1]);
t[p].son[1]=newnode();
t[t[p].son[1]].tag=t[p].tag;
t[p].tag=-1;
}
void insert(int p,int x,int y,int dep,int ti)
{
if(dep==-1||!(y&((1<<(dep+1))-1)))
{
assign(p,ti);
return;
}
int c=(x>>dep)&1,cy=(y>>dep)&1;
if(t[p].tag>=0)pushdown(p);
if(t[p].tag==-2)t[p].tag=-1;
if(cy==0)
{
if(!t[p].son[c^1])t[p].son[c^1]=newnode();
assign(t[p].son[c^1],ti);
}
if(cy==1)c^=1;
if(!t[p].son[c])t[p].son[c]=newnode();
insert(t[p].son[c],x,y,dep-1,ti);
}
void addtag(int c,int dep,int ti)
{
tim[dep][c]=ti;
int v=min(tim[dep][0],tim[dep][1]);
for(int i=dep;i<=30&&pre[i]<v;i++)pre[i]=v;
}
int query(int p,int x,int dep,int ti)
{
if(t[p].tag==-2)return inf;
if(t[p].tag>=0)
{
if(t[p].tag<ti||(dep>=0&&t[p].tag<pre[dep]))
{
assign(p,-2);
return inf;
}
int ans=0,v;
for(int i=dep;i>=0;i--)
{
v=(x>>i)&1;
if(t[p].tag<tim[i][v])ans|=1<<i;
}
return ans;
}
if(dep==-1)
{
assign(p,-2);
return inf;
}
int res=inf,c=(x>>dep)&1;
if(t[p].son[c])res=query(t[p].son[c],x,dep-1,max(ti,tim[dep][c]));
if(res!=inf)return res;
c^=1;
if(t[p].son[c])res=query(t[p].son[c],x,dep-1,max(ti,tim[dep][c]));
if(res!=inf)return res|(1<<dep);
assign(p,-2);
return inf;
}
void Clear()
{
cnt=top=0;
t[0].son[0]=t[0].son[1]=0;
t[0].tag=-2;
memset(tim,0,sizeof(tim)),memset(pre,0,sizeof(pre));
}
}using namespace Trie;
int f[1000010];
void solve()
{
n=read();
for(int i=1;i<=n;++i)a[i]=read();
int cnt=1;
memset(b,-1,sizeof(b));
l[0]=r[0]=0;
l[1]=dp[1]=1;
for(int i=2;i<=n;++i)
{
if(a[i]!=a[i-1])
{
int v=a[i]^a[i-1],h=highbit(v);
v=(a[i]>>h)&1;
if(b[h]==-1)b[h]=v;
else if(b[h]!=v)
{
memset(b,-1,sizeof(b));
r[cnt]=i-1;
++cnt;
l[cnt]=i;
}
}
dp[i]=cnt;
}
r[cnt]=n;
for(int i=1;i<=n;++i)f[i]=-1;
f[0]=0;
for(int i=1;i<dp[n];i++)
{
Clear();
for(int j=l[i-1];j<=r[i-1];j++)
{
if(j>l[i-1]&&a[j]!=a[j+1])
{
int v=a[j]^a[j+1],h=highbit(v);
addtag(((a[j]>>h)&1)^1,h,j+1);
}
if(f[j]!=-1&&f[j]!=inf)insert(0,a[j+1],f[j],30,j+1);
}
for(int j=l[i];j<=r[i];j++)
{
f[j]=query(0,a[j],30,0);
if(a[j]!=a[j+1])
{
int v=a[j]^a[j+1],h=highbit(v);
addtag(((a[j]>>h)&1)^1,h,j+1);
}
}
}
int ans=dp[n],limit=n;
for(int i=n-1;i>=1;i--)
{
if(a[i]<=a[i+1])limit=i;
else break;
}
for(int i=max(l[dp[n]-1],limit-1);i<=r[dp[n]-1];i++)
{
if(f[i]!=-1&&f[i]<=a[i+1])
{
ans=dp[n]-1;
break;
}
}
write(ans),putchar('\n');
}
int main()
{
// freopen("rain.in","r",stdin);
// freopen("rain.out","w",stdout);
std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int C=read(),T=read();
while(T--)solve();
return 0;
}