• 【题解】JZOJ7879 escape from whk 3


    JZOJ 7879

    小清新思维。

    题意

    定义一对整数是不好的当且仅当这两个整数相加是 2 2 2 的整数次幂。 m m m 次询问, [ l , r ] [l,r] [l,r] 内最多能选多少个数组成集合 A A A,使 A A A 中任意两个数都不是不好的。对于一些数据,求 [ 1 , n ] [1,n] [1,n] 的所有子区间的答案的和。

    题解

    先考虑第一问。

    有简单结论:从大往小贪心选择。

    证明:

    对于两个数相加等于 2 k 2^k 2k,显然一个数小于 2 k − 1 2^{k-1} 2k1,一个数大于 2 k − 1 2^{k-1} 2k1,所以每个数 x x x 只会满足 x + a = 2 k , x > a x+a=2^k,x>a x+a=2k,x>a 一次,也就是说每个数只会成为冲突数对中的较大数一次。

    那么对于 [ l , r ] [l,r] [l,r] 里的冲突数对 ( x , y ) , x < y , x + y = 2 k (x,y),x(x,y),x<y,x+y=2k,对于 y y y 来说,可能的冲突数在 ( 2 k ′ , r ] , 2 k ′ > y (2^{k'},r],2^{k'}>y (2k,r],2k>y 范围内,对 x x x 来说,在此基础上还多出了 ( 2 k ′ ′ , y ) , 2 k ′ ′ > x (2^{k''},y),2^{k''}>x (2k′′,y),2k′′>x 以及 x x x 为较大数的那一对冲突数对。所以选 y y y 的冲突数更少。证毕。

    现在对于一对 [ l , r ] [l,r] [l,r],找到离 r r r 最近且小于 r r r x = 2 k x=2^k x=2k。设答案为 f ( l , r ) f(l,r) f(l,r)

    显然从大往小选的时候, [ x , r ] [x,r] [x,r] 的数都不会冲突。相对应地,在 [ 2 x − r , x ) [2x-r,x) [2xr,x) 的数会跟选中的数一一冲突,于是显然有 f ( l , r ) = r − x + 1 + f ( l , 2 x − r − 1 ) f(l,r)=r-x+1+f(l,2x-r-1) f(l,r)=rx+1+f(l,2xr1)。这样直接递归,时间复杂度 O ( m log ⁡ n ) O(m\log n) O(mlogn)。边界条件是 l > r l>r l>r 的前一步。

    现在考虑第二问。设 s r = ∑ l = 1 r f ( l , r ) s_r=\sum\limits_{l=1}^rf(l,r) sr=l=1rf(l,r),答案就是求 ∑ r = 1 n s r \sum\limits_{r=1}^n s_r r=1nsr。思考如何统计 s r s_r sr。对于一个确定的 r r r,讨论 l l l

    • l ∈ [ x , r ] l\in [x,r] l[x,r],单个 l l l 贡献为 r − l + 1 r-l+1 rl+1,总的贡献等差数列求一下,就是 ( r − x + 1 ) ( r − x + 2 ) 2 \frac{(r-x+1)(r-x+2)}{2} 2(rx+1)(rx+2)
    • l ∈ [ 2 x − r , x − 1 ] l\in [2x-r,x-1] l[2xr,x1],单个 l l l 贡献为 r − x + 1 r-x+1 rx+1,总贡献为 ( r − x ) ( r − x + 1 ) (r-x)(r-x+1) (rx)(rx+1)
    • l ∈ [ 1 , 2 x − r − 1 ] l\in [1,2x-r-1] l[1,2xr1],单个 l l l 贡献为 r − x + 1 + f ( l , 2 x − r − 1 ) r-x+1+f(l,2x-r-1) rx+1+f(l,2xr1),求和一下发现总贡献为 ( 2 x − r − 1 ) ( r − x + 1 ) + ∑ i = 1 2 x − r − 1 f ( i , 2 x − r − 1 ) = ( 2 x − r − 1 ) ( r − x + 1 ) + s 2 x − r − 1 (2x-r-1)(r-x+1)+\sum\limits_{i=1}^{2x-r-1}f(i,2x-r-1)=(2x-r-1)(r-x+1)+s_{2x-r-1} (2xr1)(rx+1)+i=12xr1f(i,2xr1)=(2xr1)(rx+1)+s2xr1

    将三个贡献加起来, a n s = ( r − x + 1 ) ( r − x + 2 ) 2 + ( x − 1 ) ( r − x + 1 ) + s 2 x − r − 1 ans=\frac{(r-x+1)(r-x+2)}{2}+(x-1)(r-x+1)+s_{2x-r-1} ans=2(rx+1)(rx+2)+(x1)(rx+1)+s2xr1,于是 O ( n ) O(n) O(n) 递推搞定。

    总时间复杂度 O ( m log ⁡ n + n ) O(m\log n+n) O(mlogn+n),吊打 std!

    实现

    代码奇短,非常好写。

    注意递归函数中的全局变量,先计算再递归。

    #include 
    using namespace std;
    const int N = 300005;
    int n, m, type, pw;
    long long ans = 0, sum[N];
    int solve(int l, int r) {
    	while (pw > r) pw >>= 1;
    	if (l >= 2 * pw - r) return min(r - l + 1, r - pw + 1);
    	return r - pw + 1 + solve(l, 2 * pw - r - 1);
    }
    int main() {
    	freopen("kuhu.in", "r", stdin);
    	freopen("kuhu.out", "w", stdout);
    	scanf("%d%d%d", &n, &m, &type);
    	for (int i = 1, l, r; i <= m; i++) scanf("%d%d", &l, &r), pw = 1 << 28, printf("%d\n", solve(l, r));
    	pw = 2, sum[1] = 1;
    	for (int i = 2; i <= n; i++) {
    		if ((pw << 1) <= i) pw <<= 1;
    		sum[i] = 1ll * (i - pw + 1) * (i - pw + 2) / 2 + 1ll * (pw - 1) * (i - pw + 1) + sum[pw * 2 - i - 1];
    	}
    	for (int i = 1; i <= n; i++) ans += sum[i];
    	printf("%lld", type * ans);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    Vue中路由的两大参数
    C语言汇总
    【Try Hack Me】内网专项---Wreath
    三极管开关电路参数设计与参数介绍
    几行cmd命令,轻松将java文件打包成jar文件
    git 时忽略某个文件或文件夹
    【不是问题的问题】为什么复位中断服务程序里面直接调用的main函数,难道所有程序都在复位中断里面执行的?
    做大模型产品,如何设计prompt?
    算法学习(二)
    11-01课堂
  • 原文地址:https://blog.csdn.net/inferior_hjx/article/details/133562945