题解:P15369 『ICerOI Round 1』并非图论
简单题,秒掉了。
观察特殊性质 \(B\),容易得到最小的花费为 \(\sum_{i=l+1}^r i\),及所有的点向 \(l\) 连边。考虑哪些点是不必要连向 \(l\) 的。不难发现当 \(i\) 满足存在不是 \(l\) 的数 \(x\) 满足 \(i \text{ and } x = x\),\(i\) 是不必要的。及将 \(l+2^j\) 记为 \(x_i\),只要将 \(x_i\) 与 \(l\) 连边,其他的都可以通过与 \(x_i\) 中的某一个连接达到最小的代价。此时我们也可以回到上面,发现有两种边。一种是 \(x_i\) 与 \(l\) 的连边,代价为 \(x_i\);另一种是 \(y\) 与 \(x_i\) 的连边,其中 \(y\in(l,r] \wedge y \notin x_i\),代价为 \(y\)。
我们将上述做法拓展到一般情况。令 \(k_1\) 满足 \(2^{k_1} \le l < 2^{k_1+1}\),\(k_2\) 满足 \(2^{k_2} \le r < 2^{k_2+1}\),可以将询问 \([l,r]\) 分成三个区间,\([l,2^{k_1+1}) \bigcup [2^{k_1+1},2^{k_2}) \bigcup[2^{k_2},r]\)。
对于区间 \([l,2^{k_1+1})\) 我们猜测大致做法一样,但是手模小数据发现最小代价会算少,我们将 \(l\) 的二进制位上某一位 \(i\) 的 \(0\) 变成 \(1\) 并且将该位到最低位的 \(1\) 变成 \(0\) 时的数还是记为 \(x_i\),答案要加上 \(\sum_i(l-l\text{ and }x_i)\)。
对于区间 \([2^{k_1+1},2^{k_2})\),我们将这个大区间拆分成若干个形如 \([2^k,2^{k+1})\) 的小区间,每个小区间内所有点连向小区间的左端点,并且容易从这个小区间内挑出一个数 \(x\) 满足前面的区间内存在数 \(y\) 满足\(y\subseteq x\) 并且将 \(x\) 与 \(y\) 连边,不难发现这等价于这个小区间的左端点向 \(l\) 连边。
对于区间 \([2^{k_2},r]\),直接套用特殊性质 \(B\)。
然后做完了,注意答案多取模。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
const int INV = 500000004ll;
int id, n, Q;
int C(int x){
int c = 0;
while(x) ++c, x /= 2ll;
return c - 1;
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> id >> n >> Q;
while(Q--){
int l, r, j1 = 0, j2 = 0;
cin >> l >> r;
if(l == r){
cout << 0 << ' ' << 0 << '\n';
continue;
}
j1 = C(l), j2 = C(r);
if(j1 == j2){
int c1 = 0, c0 = 0;
c1 = (l + 1 + r) % mod * ((r - l + mod) % mod) % mod * INV % mod;
for(int j = 0; j < j1; j++){
if(((l >> j) & 1) == 0){
int x = l - (l & ((1ll << j) - 1)) + (1ll << j);
if(x <= r){
++c0;
c1 += l - (x & l); c1 %= mod;
}
else break;
}
}
cout << c1 << ' ' << c0 << '\n';
continue;
}
int ans1 = 0, ans2 = 0;
if(l + 1 != (1ll << (j1 + 1))){
int c1 = 0, c0 = 0;
c1 = (l + 1 + ((1ll << (j1 + 1)) - 1)) % mod * ((((1ll << (j1 + 1)) - 1) - l + mod) % mod) % mod * INV % mod;
for(int j = 0; j < j1; j++){
if(((l >> j) & 1) == 0){
int x = l - (l & ((1ll << j) - 1)) + (1ll << j);
if(x <= ((1ll << (j1 + 1)) - 1)){
++c0;
c1 += l - (x & l); c1 %= mod;
}
else break;
}
}
ans1 += c1, ans1 %= mod;
ans2 += c0, ans2 %= mod;
}
for(int j = j1 + 1; j < j2; j++){
int x = (1ll << j), y = (1ll << (j + 1)) - 1;
ans1 += (l + (x + 1 + y) % mod * ((y - x + mod) % mod) % mod * INV % mod) % mod + x % mod; ans1 %= mod;
ans2++; ans2 %= mod;
}
int c0 = 0; int w = (r - (1ll << j2) + mod) % mod;
for(int j = 0; j < j2; j++){
if((1ll << j2) + (1ll << j) <= r) ++c0;
}
ans1 += ((1ll << j2) + 1 + r) % mod * w % mod * INV % mod + l % mod + (1ll << j2) % mod; ans1 %= mod;
ans2++; ans2 %= mod;
cout << ans1 << ' ' << ans2 << '\n';
}
return 0;
}

浙公网安备 33010602011771号