P11843 [USACO25FEB] The Best Subsequence G 题解

· · 题解

思路分析:

根据题目中说的:

我们知道,字符串 A 的字典序大于长度相等的字符串 B,当且仅当在第一个 A_i\ne B_i 的位置 i 上(如果存在),我们有 A_i>B_i

发现要最大化字典序,一定是前面一段全为 1,后面接一个所求区间的后缀子串,并且是最短的满足条件的后缀子串。于是考虑二分求分割点,要求前半部分 1 的数量加上后半部分长度达到 k

最后要按位值输出,类似哈希维护前缀位值和即可。 这里赛时代码,已经打好线段树了才想到前缀和,于是就懒得改直接 $O(q\log n\log m)$ 了,用上述做法,以及有效二分点只有序列分段的点,可以优化成 $O(q\log m)$。 ## AC Code: ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int N=4e5+10,mod=1e9+7; int qpow(int x,int y){ int res=1; while(y){ if(y&1)res=res*x%mod; x=x*x%mod,y>>=1; }return res; } int n,M,m,q,a[N],p[N],tr[N<<2],h[N<<2]; #define mid (l+r>>1) #define ls (p<<1) #define rs (ls|1) void build(int p,int l,int r){ if(l==r){ if(l&1) tr[p]=a[l+1]-a[l], h[p]=(qpow(2,a[l+1]-a[l])-1+mod)%mod; return; } build(ls,l,mid),build(rs,mid+1,r); tr[p]=tr[ls]+tr[rs]; h[p]=h[ls]*qpow(2,a[r+1]-a[mid+1])%mod+h[rs]; h[p]%=mod; } int query1(int p,int l,int r,int L,int R){ if(L<=l&&r<=R)return tr[p]; int res=0; if(L<=mid)res+=query1(ls,l,mid,L,R); if(mid<R)res+=query1(rs,mid+1,r,L,R); return res; } int query2(int p,int l,int r,int L,int R){ if(L<=l&&r<=R)return h[p]*qpow(2,a[R+1]-a[r+1])%mod; int res=0; if(L<=mid)res+=query2(ls,l,mid,L,R); if(mid<R)res+=query2(rs,mid+1,r,L,R); return res%mod; } int qry(int l,int r){ if(l>r)return 0; int L=upper_bound(a,a+m+2,l)-a-1; int R=upper_bound(a,a+m+2,r)-a-1; int res=0; if(L+1<R)res+=query1(1,0,m,L+1,R-1); if(L&1)res+=a[L+1]-l; if((L^R)&&(R&1))res+=r-a[R]+1; return res; } int val(int l,int r){ if(l>r)return 0; int L=upper_bound(a,a+m+2,l)-a-1; int R=upper_bound(a,a+m+2,r)-a-1; int res=0; if(L+1<R)res+=query2(1,0,m,L+1,R-1)*qpow(2,r-a[R]+1)%mod; if(L&1)res+=qpow(2,r-l-1)-qpow(2,r-a[L+1]-1)+mod; if((L^R)&&(R&1))res+=qpow(2,r-a[R]+1)-1+mod; return res%mod; } #undef mid #undef ls #undef rs signed main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n>>M>>q; for(int i=1,l,r;i<=M;i++) cin>>p[i]>>p[i+M],p[i+M]++; sort(p+1,p+2*M+1); a[0]=0; for(int i=1;i<=2*M;i++){ int t=1; while(p[i]==p[i+1])t++,i++; if(t&1)a[++m]=p[i]; } if(a[m]==n+1)m--; else a[m+1]=n+1; build(1,0,m); while(q--){ int L,R,k; cin>>L>>R>>k; int l=L,r=R,x=L-1; while(l<=r){ int mid=l+r>>1; if(qry(L,mid)+R-mid>=k) l=mid+1,x=mid; else r=mid-1; } cout<<(qpow(2,k)-qpow(2,R-x)+val(x+1,R)+mod)%mod<<'\n'; } return 0; } ```