【题解】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;
}

你可能感兴趣的:(题解,算法,c++)