CF1725D Deducing Sortability
*2900 太困难了!!!
题意
定义一个长度为 \(n\) 的序列 \(a\) 是好的,当且仅当其能通过以下操作使得该序列严格递增:
- 初始有长度为 \(n\) 的数组 \(c\),初始值为 0。
- 每次操作选择一个 \(i\in[1,n]\),令 \(a_i\leftarrow (a_i-2^{c_i})\times2\),随后令 \(c_i\leftarrow c_i+1\)。
求在 \(\sum a_i\) 最小的前提下字典序最小的 \(a\)。由于长度过长,所以 \(q\) 次询问 \(a_i\) 的值。
\(n\le 10^9,q\le 10^5\)
分析
通过暴力拆括号可以发现对 \(x\) 做 \(p\) 次操作最后的值为 \((x-p)2^p\)。由于需要总和最小,所以假设最终的 \(a_i\) 确定了,那么原始的 \(a_i\) 需要最小,考虑到如果 \(y=x-p\) 为偶数,那么进一步 \(y2^p=\frac{y}{2}2^{p+1}\),由于 \(\frac{y}{2}\) 严格比 \(y\) 小,所以后者的初始值 \(\frac{y}{2}+p+1\) 要比前者的初始值 \(y+p\) 严格不劣。这样就能说明对于一个 \(x\),其能生成的(有用的)数只有 \(\lceil\frac{x}{2}\rceil\) 个(当 \(p\) 的奇偶性与 \(x\) 不同时)。为了让总和最小,肯定是尽可能的采用原始值更小的数,这时会出现一个上界 \(m\) 满足 \(\sum_{i=1}^{m+1}\lceil\frac{i}{2}\rceil\ge n\),此时前 \(m\) 个数一定是取满的,对于第 \(m+1\) 个数,由于要字典序最小,所以 \(m+1\) 生成的数要尽可能大,也就是要让 \(p\) 最大,选出 \(n-\sum_{i=1}^{m}\lceil\frac{i}{2}\rceil\) 个合法的 \(p\) 即可。
考虑如何单点求值(假设查询 \(x\))。打表稍微观察一下,\(i\) 行 \(j\) 列表示对 \(i\) 操作 \(j\) 次的结果。不妨按列考虑,对于第一列(即 \(p=0\) 生成的数),奇数行都一定有值且排在最前面的奇数下标中。假设这一列中有 \(a_0\) 个有效的数(也就是序列中有 \(a_0\) 个数是操作了 0 次后的结果),那么如果 \(x<2a_0\),考虑如果 \(x\) 为奇数,那么答案就是 \(x\);否则就将 \(x\) 除以 2 然后考虑下一列(不难发现此时是相同的子问题)。如果 \(x\ge 2a_0\),将 \(x\leftarrow x-a_0\),然后接着考虑下一列(此时还是相同的子问题)。注意此时如果找到的答案在第 \(i\) 列第 \(t\) 个下标处,最终答案为 \(t+i\)(因为第 \(i\) 列从第 \(i+1\) 行开始标号)。具体可以见代码。
现在想要查找最小的 \(q\) 使得 \(x\ge \sum_{i=0}^qa_i+a_q\),由于后面这东西有单调性所以可以二分。时间复杂度 \(O(\sqrt n+q\log n)\)(预处理出 \(a_i\) 和前缀和) 或 \(O(q\log n)\)(每次快速算出 \(a_i\) 和前缀和)。
附一张表:
1
1
2
-1 2
3
3 -1 4
4
-1 6 -1 8
5
5 -1 12 -1 16
6
-1 10 -1 24 -1 32
7
7 -1 20 -1 48 -1 64
8
-1 14 -1 40 -1 96 -1 128
9
9 -1 28 -1 80 -1 192 -1 256
10
-1 18 -1 56 -1 160 -1 384 -1 512
\(O(\sqrt n+q\log n)\):
const i128 e=1;
int n,Q;
i128 calc2(int x){
return e*x*(x+1)*(2*x+1)/6;
}
i128 calc1(int x){
return e*x*(x+1)/2;
}
//[1,m]全取,m+1取k靠后的
int m;
i128 solve(){
int l=1,r=1e9,res=-1;
while(l<=r){
int mid=(l+r)>>1;
if(n<=mid*(mid+1))res=mid,r=mid-1;
else l=mid+1;
}
i128 ans=4*calc2(res-1)-calc1(res-1);
i128 rem=n-res*(res-1);
if(rem<=res)return m=2*res-2,ans+(2*res-1)*rem;
return m=2*res-1,ans+res*(2*res-1)+(2*res)*(rem-res);
}
int a[maxn],b[maxn],c[maxn];
inline void solve_the_problem(){
n=rd(),Q=rd();
write(solve());
int rem=n;
rep(i,1,m)rem-=(i+1)/2;
rep(i,0,m){
a[i]=(m-i+1)/2+(i%2==m%2&&(m-i)/2<rem);
b[i]=(i?b[i-1]:0)+a[i],c[i]=a[i]+b[i];
}
while(Q--){
int x=rd();
int ps=lower_bound(c,c+m+1,x)-c,k=x-(ps?b[ps-1]:0);
write(ps+k/lowbit(k)+__builtin_ctz(k));
}
}
\(O(q\log n)\):
const i128 e=1;
int n,Q;
i128 calc2(int x){
return e*x*(x+1)*(2*x+1)/6;
}
i128 calc1(int x){
return e*x*(x+1)/2;
}
//[1,m]全取,m+1取k靠后的
int m,re;
i128 solve(){
int l=1,r=1e9,res=-1;
while(l<=r){
int mid=(l+r)>>1;
if(n<=mid*(mid+1))res=mid,r=mid-1;
else l=mid+1;
}
i128 ans=4*calc2(res-1)-calc1(res-1);
i128 rem=n-res*(res-1);
if(rem<=res)return m=2*res-2,re=rem,ans+(2*res-1)*rem;
return m=2*res-1,re=rem-res,ans+res*(2*res-1)+(2*res)*(rem-res);
}
int a[maxn],b[maxn],c[maxn];
il i128 calc0(int i){
return (m-i+1)/2+(i%2==m%2&&(m-i)/2<re);
}
il i128 calc(int i){
i128 ans=0;
if(m%2==0){
ans=(calc1(m/2)-calc1((m-i+1)/2-1))*2;
if(i%2==0)ans-=(m-i+1)/2;
}else{
if(!i)return calc0(i);
ans=(m+1)/2;
ans+=(calc1(m/2)-calc1((m-i+1)/2-1))*2;
if(i%2==1)ans-=(m-i+1)/2;
}
ans+=re-min(re,(m-i+1)/2);
return ans;
}
inline void solve_the_problem(){
n=rd(),Q=rd();
write(solve());
while(Q--){
int x=rd();
int l=0,r=m,res=-1;
while(l<=r){
int mid=(l+r)>>1;
if(calc(mid)+calc0(mid)>=x)res=mid,r=mid-1;
else l=mid+1;
}
int k=x-(res?calc(res-1):0);
write(res+k/lowbit(k)+__builtin_ctz(k));
}
}

浙公网安备 33010602011771号