CF2257D Bermuda Rectangle
本来以为就是找两个分界点,结果最后写下来发现细节挺多的。。。
\(S\) 的矩形呈阶梯状,肯定要先按形状把贡献存下来。
高度分界点记为 \(l\),完整分界点记为 \(r\)。
手玩一下发现有四类矩形产生贡献:
高度 \(\ge y\) 且完整在 \((x, y)\) 内的。
高度 \(\ge y\) 且部分在 \((x, y)\) 内的。(这类容易漏掉还有很多小细节,比如高度要取 \(\min(y, h_i)\))
高度 \(\le y\) 且完整在 \((x, y)\) 内的。
高度 \(\le y\) 且部分在 \((x, y)\) 内的。
分界点用二分查找就行了,注意 \(l\) 要满足 \(rk[l] \le x\),所以建议手写一个二分。
时间复杂度 \(O(qlog {\sqrt{S}})\)。记得算一下内存。
其实反思一下,之所以把第二类漏掉了主要还是因为考虑的样例情况少了。还是要勤举例勤动手。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int N = 11000000;
int T, q, cnt;
ll S, rk[N], sum[N];
void ins(ll x){
++ cnt;
rk[cnt] = x;
}
int FInd(ll x, ll y){
int l = 0, r = cnt + 1, mid;
while(l + 1 < r){
mid = (l + r) >> 1;
if(rk[mid] <= x && S / rk[mid] >= y) l = mid;
else r = mid;
}
return l;
}
void Main(){
cnt = 0;
cin >> S >> q;
int b = sqrt(S);
F(i, 1, b){
if(S % i == 0){
ins(i);
ins(S / i);
}
}
sort(rk + 1, rk + cnt + 1);
F(i, 1, cnt){
ll x = rk[i];
sum[i] = sum[i - 1] + S / x * (rk[i] - rk[i - 1]); // stair-like value, store as the stair
}
// printf("cnt = %d :\t", cnt);
// F(i, 1, cnt) printf("%lld\t", rk[i]);
// printf("\n");
while(q --){
ll x, y, tmp1 = 0, tmp2 = 0, tmp3 = 0, ans = 0;
cin >> x >> y;
int l, r;
l = FInd(x, y);
r = upper_bound(rk + 1, rk + cnt + 1, x) - rk - 1;//wan zheng kuai de bian jie
// l = lower_bound(rk + 1, rk + r + 1, S / y) - rk;
// printf("l = %d\tr = %d\n", l, r);
if(l <= r){ // have over-complete rectagle
tmp1 = y * rk[l];
tmp2 = sum[r] - sum[l];
}
else{ // low height
tmp1 = y * rk[r];
}
if(r < cnt) tmp3 = (x - rk[r]) * min(y, (S / rk[r + 1]));
// printf("tmp1 = %lld\ttmp2 = %lld\ttmp3 = %lld\n", tmp1, tmp2, tmp3);
ans = tmp1 + tmp2 + tmp3;
cout << ans << '\n';
}
return ;
}
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> T;
while(T --) Main();
return fflush(0), 0;
}

浙公网安备 33010602011771号