【考试总结】2022-05-01
作者:互联网
a
观察能构成合法区间的条件就是奇数成对,同时每对奇数之间没有 \(0\)
使用一类线段树维护历史信息的手段来解决本题,为了规避麻烦的标记下放,可以将每个 “偶数个奇数” 的出现区间左右端点刻画出来并使用 \(r-l+1\) 来计算
同时在每个节点要支持 \(01\) 翻转的部分维护 “对未翻转时奇数/偶数” 的权值增加量方便下方
Code Display
const int N=5e5+10;
int n,Q,a[N],his[N],ans[N];
vector<pair<int,int> > qu[N];
bool ban[N],od[N];
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
bool rev[N<<2];
int num[N<<2][2],delt[N<<2][2],sum[N<<2];
inline void push_up(int p){
sum[p]=sum[ls]+sum[rs];
num[p][0]=num[ls][0]+num[rs][0];
num[p][1]=num[ls][1]+num[rs][1];
return ;
}
inline void push_rev(int p){rev[p]^=1; swap(num[p][0],num[p][1]);}
inline void push_add(int p,int v,int fl){
delt[p][rev[p]^fl]+=v;
sum[p]+=num[p][fl]*v;
return ;
}
inline void push_down(int p){
for(int i=0;i<2;++i) if(delt[p][i]){
push_add(ls,delt[p][i],i);
push_add(rs,delt[p][i],i);
delt[p][i]=0;
}
if(rev[p]){
push_rev(ls); push_rev(rs);
rev[p]=0;
}
return ;
}
inline void upd(int R,int v,int fl,int p=1,int l=1,int r=n){
if(r<=R) return push_add(p,v,fl),void();
int mid=(l+r)>>1; push_down(p);
if(R>mid) upd(R,v,fl,rson);
upd(R,v,fl,lson);
return push_up(p);
}
inline int query(int st,int ed,int p=1,int l=1,int r=n){
if(st<=l&&r<=ed) return sum[p];
int mid=(l+r)>>1,res=0; push_down(p);
if(ed>mid) res+=query(st,ed,rson);
if(st<=mid) res+=query(st,ed,lson);
return res;
}
inline void dfs(int p,int l,int r){
if(!num[p][1]) return ;
if(l==r){
delt[p][0]=delt[p][1]=0;
num[p][0]=num[p][1]=0;
return ;
}
int mid=(l+r)>>1; push_down(p);
dfs(lson); dfs(rson);
return push_up(p);
}
inline void Reverse(int R,int p=1,int l=1,int r=n){
if(r<=R) return push_rev(p);
int mid=(l+r)>>1; push_down(p);
if(R>mid) Reverse(R,rson);
Reverse(R,lson);
return push_up(p);
}
inline void build(int p,int l,int r){
if(l==r){
num[p][0]=1;
sum[p]=-l;
return ;
}
int mid=(l+r)>>1;
build(lson); build(rson);
return push_up(p);
}
inline void output(int p,int l,int r){
if(l==r) return cout<<sum[p]<<" ",void();
int mid=(l+r)>>1; push_down(p);
output(lson); output(rson);
return ;
}
#undef ls
#undef rs
#undef lson
#undef rson
signed main(){
freopen("a.in","r",stdin); freopen("a.out","w",stdout);
n=read(); Q=read();
for(int i=1;i<=n;++i) a[i]=read();
for(int i=1;i<=Q;++i){
int l=read(),r=read();
qu[r].emplace_back(l,i);
}
build(1,1,n);
for(int i=1;i<=n;++i){
if(!a[i]&&i) dfs(1,1,n);
if(a[i]&1){
upd(i,i,0);
upd(i,-i,1);
Reverse(i);
}
for(auto t:qu[i]){
upd(i,i+1,0);
ans[t.sec]+=query(t.fir,i);
upd(i,-1-i,0);
}
}
rep(i,1,Q) print(ans[i]);
return 0;
}
b
对于 \(Q\) 个属于 \([1,m]\) 的 随机区间,将左端点排序后,对应的右端点最长上升子序列长度是 \(\Theta(\sqrt Q)\) 级别的
那么将所有询问分成 \(\dfrac{Q}{\sqrt Q}\) 组,每组中询问形成嵌套关系,使用势能线段树暴力扩展即可
但是据说会被卡常,所以代码写了个能过的暴力
Code Display
const int N=15010;
int n,m,Q,sum[N<<2];
struct operation{
int l,r,v,id;
}opt[N<<1];
inline void upd(int p,int l,int r,int st,int ed){
if(sum[p]==r-l+1) return ;
if(st<=l&&r<=ed) return sum[p]=r-l+1,void();
int mid=(l+r)>>1;
if(st<=mid) upd(p<<1,l,mid,st,ed);
if(ed>mid) upd(p<<1|1,mid+1,r,st,ed);
sum[p]=sum[p<<1]+sum[p<<1|1];
return ;
}
inline void build(int p,int l,int r){
sum[p]=0; if(l==r) return ;
int mid=(l+r)>>1;
build(p<<1,l,mid); build(p<<1|1,mid+1,r);
}
signed main(){
freopen("b.in","r",stdin); freopen("b.out","w",stdout);
n=read(); m=read(); Q=read();
for(int i=1;i<=n;++i) opt[i]={i,i,read(),0};
int cnt=n;
for(int i=1;i<=m;++i){
int l=read(),r=read(),v=read();
opt[++cnt]={l,r,v,i};
}
sort(opt+1,opt+cnt+1,[&](const operation A,const operation B){return A.v<B.v;});
while(Q--){
int l1=read(),r1=read(),l2=read(),r2=read();
int lst=0;
int ans=0;
int siz=r2-l2+1;
build(1,1,siz);
for(int i=1;i<=cnt;++i){
if(opt[i].id&&(opt[i].id<l1||opt[i].id>r1)) continue;
if(opt[i].r<l2||opt[i].l>r2) continue;
upd(1,1,siz,max(opt[i].l,l2)-l2+1,min(opt[i].r,r2)-l2+1);
ans+=(sum[1]-lst)*opt[i].v;
if(sum[1]==siz) break;
lst=sum[1];
}
print(ans);
}
return 0;
}
c
发现本质上要完成的工作是对 \(n\times K\) 个点值做背包,但是每个元素的值域只有 \(\pm1\) ,也就是在 \(n\) 个数字里面找到 \(m\) 个并将它们乘起来再对所有选择方案的权值求和
设有 \(x\) 个元素贡献 \(1\) 而 \(n-x\) 个元素贡献 \(-1\),对于所有 \(x\) 求出来 \([z^m](1-z)^{n-x}(1+z)^{x}\)
而这通过分配幂次变成 \(\displaystyle \sum_{i=0}^m(-1)^{m-i}\binom{n-x}{m-i}\binom{x}i\)
再拆成阶乘逆元可以通过一次卷积进行计算
在对 \(a_i\) 形成的桶做 \(\rm FWT\) 后得到的点值解方程可以得到上面所写的 \(x\),那么直接代换成背包后的结果再做逆变换得到答案
Code Display
const int N=2e5+10;
int n,m,K;
inline void FWT(vector<int> &f,int lim){
for(int p=2;p<=lim;p<<=1){
int len=p>>1;
for(int k=0;k<lim;k+=p) for(int l=k;l<k+len;++l){
int x=f[l],y=f[l+len];
f[l+len]=x-y;
f[l]=x+y;
}
}
return ;
}
inline void iFWT(vector<int> &f,int lim){
for(int p=2;p<=lim;p<<=1){
int len=p>>1;
for(int k=0;k<lim;k+=p) for(int l=k;l<k+len;++l){
int x=f[l],y=f[l+len];
f[l+len]=del(x,y);
f[l]=add(x,y);
}
}
for(int tmp=ksm(lim,mod-2),i=0;i<lim;++i) ckmul(f[i],tmp);
return ;
}
int W[1<<20],r[1<<20];
inline void NTT(vector<int> &f,int lim,int opt){
f.resize(lim);
for(int i=0;i<lim;++i){
r[i]=r[i>>1]>>1|((i&1)?(lim>>1):0);
if(i<r[i]) swap(f[i],f[r[i]]);
}
for(int p=2;p<=lim;p<<=1){
int len=p>>1; W[0]=1;
W[1]=ksm(3,(mod-1)/p);
if(opt==-1) W[1]=ksm(W[1],mod-2);
for(int j=2;j<len;++j) W[j]=mul(W[j-1],W[1]);
for(int k=0;k<lim;k+=p){
for(int l=k;l<k+len;++l){
int tt=mul(f[l+len],W[l-k]);
f[l+len]=del(f[l],tt);
ckadd(f[l],tt);
}
}
}
if(opt==-1) for(int tmp=ksm(lim,mod-2),i=0;i<lim;++i) ckmul(f[i],tmp);
}
int ifac[N],fac[N];
signed main(){
freopen("c.in","r",stdin); freopen("c.out","w",stdout);
n=read(); m=read(); K=read();
vector<int> f,g,a(K);
for(int i=1;i<=n;++i) a[read()]++;
if(m==1){
rep(i,0,K-1) print(a[i]);
putchar('\n');
exit(0);
}
fac[0]=1;
for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
ifac[n]=ksm(fac[n],mod-2);
for(int i=n;i>=1;--i) ifac[i-1]=mul(ifac[i],i);
FWT(a,K);
int lim=1;
while(lim<=n) lim<<=1;
f.resize(m+1);
g.resize(n-m+1);
for(int i=0;i<=m;++i){
f[i]=mul(ifac[i],ifac[m-i]);
if((m-i)&1) f[i]=del(0,f[i]);
}
for(int i=0;i<=n-m;++i) g[i]=mul(ifac[i],ifac[n-m-i]);
NTT(f,lim,1); NTT(g,lim,1);
for(int i=0;i<lim;++i) ckmul(f[i],g[i]);
NTT(f,lim,-1);
for(int i=0;i<=n;++i) ckmul(f[i],mul(fac[i],fac[n-i]));
for(int i=0;i<K;++i) a[i]=f[(n-a[i])/2];
iFWT(a,K);
for(int i=0;i<K;++i) print(a[i]); putchar('\n');
return 0;
}
标签:opt,01,return,05,int,lim,rson,2022,push 来源: https://www.cnblogs.com/yspm/p/16216788.html