1 条题解
-
0
自动搬运
来自洛谷,原作者为

Po7ed
**搬运于
2025-08-24 23:10:44,当前版本为作者最后更新于2025-08-17 15:25:09,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
拜谢 @happy_zero 大神提供的单 log 做法。

先将修改差分处理,形成若干连续段。
考虑答案的形态。由于是给定子串的一个长度为 的子序列,且要求字典序最大,考虑一个理想的情况,即子串内 的个数大于 ,那么答案子序列所有元素均为 。
当 不够用的时候,从后往前接受 。也就是说,答案的形态是前半段全是 ,后半段是给定子串的一个后缀。
考虑如何找到这个后缀。由于子串内 的个数 已经确定,需要的 的个数 也确定,即 。而需要的 均由后缀提供,所有后缀中 的出现次数有单调性,可以二分。
如果直接二分后缀,需要再二分找到其属于哪个连续段,复杂度达到线性对数平方。
这时候我们直接二分后缀所属连续段,然后就可以 确定后缀位置。复杂度线性对数。
::::success[代码]
#include <bits/stdc++.h> using std::cin; typedef long long ll; constexpr int N=2e5+114,mod=1e9+7; int n,m,q; std::map<int,int> c; // 端点 std::vector<int> v,s; // 端点、前缀 0 数量 std::vector<ll> p; // 前缀和 int t; ll qpow(ll x,ll y) { ll r=1; for(;y;x=1ll*x*x%mod,y/=2)if(y&1)r=1ll*r*x%mod; return r; } int main() { cin.tie(nullptr)->sync_with_stdio(false); cin>>n>>m>>q; c[1]=c[n+1]=2; for(int i=1,l,r;i<=m;i++) { cin>>l>>r; c[l]^=1,c[r+1]^=1; } t=c[1]&1; // 第一块颜色 for(auto [x,y]:c)if(y) { v.push_back(x); } s.resize(v.size()),p.resize(v.size()); if(t)s[0]=0,p[0]=(qpow(2,v[1]-v[0])+mod-1)%mod; else s[0]=v[1]-v[0],p[0]=0; for(int i=1,j=t^1;i<v.size()-1;i++,j^=1) // 计算前缀 0 数量和前缀和 { if(j) { s[i]=s[i-1]; p[i]=(1ll*(p[i-1]+1)*qpow(2,v[i+1]-v[i])+mod-1)%mod; } else { s[i]=s[i-1]+v[i+1]-v[i]; p[i]=1ll*p[i-1]*qpow(2,v[i+1]-v[i])%mod; } } // 属于哪块 auto bel=[](int x){return std::upper_bound(v.begin(),v.end(),x)-v.begin()-1;}; for(int l,r,k;q--;) { cin>>l>>r>>k,l--; int L=bel(l),R=bel(r); int lc1=~L?(t^L&1?l-s[L]:v[L+1]-1-s[L]):0; // l 前缀 1 数量 int rc1=t^R&1?r-s[R]:v[R+1]-1-s[R]; // r 前缀 1 数量 int c1=rc1-lc1; // [l,r] 1 数量 int n0=k-c1; // 需要的 0 的数量 if(n0<=0) // 不需要 0 { printf("%d\n",(qpow(2,k)+mod-1)%mod); } else { int ql=std::max(L,0)-1,qr=R,rc0=r-rc1,mid; while(ql+1<qr) // 二分分界点在那一块 { mid=(ql+qr)/2; (s[mid]>=rc0-n0?qr:ql)=mid; } // 分界点 int p0=v[qr+1]-1,t0=n0-(rc0-s[qr]),p1=p0-t0; int len=r-p1,l1=k-len; printf("%d\n",((1ll*(qpow(2,l1)+mod-1)*qpow(2,len)+ // 前面的 1 1ll*(R?p[R-1]:0)*qpow(2,r-v[R]+1)+ // r 整块前缀和 (t^R&1?qpow(2,r-v[R]+1)+mod-1:0) // r 散块前缀和 -1ll*(qr?p[qr-1]*qpow(2,v[qr]-1-r):0) // 整块前缀和 -1ll*(t^qr&1?qpow(2,p1-v[qr]+1)+mod-1:0)*qpow(2,p1-r) // r 散块前缀和 )%mod+mod)%mod); } } }::::
以防有人不知道怎么下数据。
- 1
信息
- ID
- 11597
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者