题解:P16833 【MX-X29-T4】Max Convolution
lailai0916 · · 题解
题意简述
给定序列
解题思路
将一对指数从大到小记为
其中
先考虑前
序列
对
同理定义
问题转化为二进制位置集与普通数列的 max 卷积。以
设机器字长为
对后
正确性证明
指数对按
固定前缀常值段
处理第二关键字时,算法按
每条前缀对角线属于唯一常值段。翻转操作又与后半部分对角线一一对应。故算法对所有
复杂度分析
固定长度为
所有常值段长度之和为
参考代码
#include <bits/stdc++.h>
using namespace std;
using ull=unsigned long long;
const int N=100005;
const int M=200005;
const int W=(N+63)/64;
const int mod=998244353;
struct node
{
int val,pos,op;
};
int a[N],b[N],ans[N],res[N],pw[M],c[N];
int pa[N],pb[N],qa[N],qb[N];
ull ba[W],bb[W],bt[W],un[W];
node e[2*N];
bool cmp(const node &x,const node &y)
{
return x.val>y.val;
}
void mark(int *p,int n,int *q,int m,ull *bs,int len,int val,int &cnt)
{
if(!n||!m||!cnt)return;
int w=(len+63)/64;
if(max(n,m)<=w)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
int s=p[i]+q[j];
if(s>=len)continue;
ull x=1ULL<<(s&63);
if(un[s>>6]&x)
{
un[s>>6]^=x;
c[s]=val;
cnt--;
}
}
}
return;
}
int *v=q;
int siz=m;
if(n<m)
{
for(int i=0;i<w;i++)bt[i]=0;
for(int i=0;i<m;i++)bt[q[i]>>6]|=1ULL<<(q[i]&63);
bs=bt;
v=p;
siz=n;
}
for(int i=0;i<siz&&cnt;i++)
{
int sh=v[i]>>6,r=v[i]&63;
for(int j=sh;j<w;j++)
{
ull cur=bs[j-sh]<<r;
if(r&&j>sh)cur|=bs[j-sh-1]>>(64-r);
cur&=un[j];
while(cur)
{
int k=__builtin_ctzll(cur),pos=(j<<6)+k;
un[j]^=1ULL<<k;
c[pos]=val;
cnt--;
cur&=cur-1;
}
}
}
}
void work(int l,int r,int mx,int *out)
{
int len=r-l+1,na=0,nb=0;
for(int i=0;i<len;i++)
{
if(a[l+i]==mx)pa[na++]=i;
if(b[l+i]==mx)pb[nb++]=i;
e[i]={b[i],i,0};
e[len+i]={a[i],i,1};
}
int w=(len+63)/64;
for(int i=0;i<w;i++)
{
ba[i]=0;
bb[i]=0;
}
for(int i=0;i<na;i++)ba[pa[i]>>6]|=1ULL<<(pa[i]&63);
for(int i=0;i<nb;i++)bb[pb[i]>>6]|=1ULL<<(pb[i]&63);
for(int i=0;i<w;i++)un[i]=~0ULL;
if(len&63)un[w-1]=(1ULL<<(len&63))-1;
sort(e,e+2*len,cmp);
int cnt=len,i=0;
while(i<2*len&&cnt)
{
int j=i,ca=0,cb=0;
while(j<2*len&&e[j].val==e[i].val)
{
if(e[j].op)qb[cb++]=e[j].pos;
else qa[ca++]=e[j].pos;
j++;
}
mark(pa,na,qa,ca,ba,len,e[i].val,cnt);
mark(pb,nb,qb,cb,bb,len,e[i].val,cnt);
i=j;
}
i=0;
while(i<len)
{
out[l+i]=(pw[mx]+pw[c[i]])%mod;
i++;
}
}
void solve(int n,int *out)
{
int l=0,mx=max(a[0],b[0]);
for(int i=1;i<=n;i++)
{
if(i<n&&max(a[i],b[i])<=mx)continue;
work(l,i-1,mx,out);
if(i<n)
{
l=i;
mx=max(a[i],b[i]);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<n;i++)cin>>b[i];
pw[0]=1;
for(int i=1;i<2*n;i++)pw[i]=pw[i-1]*2%mod;
solve(n,ans);
reverse(a,a+n);
reverse(b,b+n);
solve(n,res);
for(int i=0;i<2*n-1;i++)
{
if(i)cout<<' ';
cout<<(i<n?ans[i]:res[2*n-2-i]);
}
cout<<'\n';
return 0;
}