23.7.11 Day 2
二分
这个二分模板好记欸。
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid)) l = mid + 1,ans = mid;
else r = mid - 1;
}
Rest The Shades
前缀和记录,然后单独计算一下两头的线段,也就是蓝色那一段,用总的减不在里面的就可以。还有一点相似比。而且要记得把 \(min\) 和 \(max\) 改成 \(double\) !
还没有过,现在cf寄了,样例过了。
好好好过了
#include<bits/stdc++.h>
#define kg putchar(' ')
#define ch puts("")
#define wj puts("0.000000000000000")
#define se second
#define fi first
using namespace std;
typedef long long lwl;
typedef pair<int,int> pii;
const int N = 2e5 + 5, inf = 0x3f3f3f3f;
double zero = 1e-8;
int n,Q;
int wl[N],wr[N];
lwl sum[N];
int a,b,wy;
lwl fr(){
lwl x = 0, flag = 1;
char t;
t = getchar();
while (t < 48 || t > 57){
if (t == '-') flag = -1;
t = getchar();
}
while (t >= 48 && t <= 57){
x = x * 10 + t - 48;
t = getchar();
}
return x*flag;
}
void fw(lwl x){
if (x < 0) putchar('-'),x = -x;
if (x > 9){
fw(x / 10);
}
putchar(x % 10 + '0');
return ;
}
int main(){
wy = fr(),a = fr(),b = fr();
int len = b - a;
n = fr();
for (int i = 1; i <= n; i ++) {
wl[i] = fr();
wr[i] = fr();
sum[i] = sum[i - 1] + wr[i] - wl[i];
}
Q = fr();
int x,y;
double ans;
while (Q --) {
x = fr(),y = fr();
double k = 1.0 * y / (y + abs(wy));
double dxa = (a - x) * k + x,dxb = (b - x) * k + x;
if (dxb <= wl[1] || dxa >= wr[n]) {
wj;
continue;
}
double L,R;
int l = 1,r = n;
while (l <= r) {
int mid = (l + r) >> 1;
if (wr[mid] <= dxa + zero) l = mid + 1;
else r = mid - 1;
}
L = sum[l];
L -= min((double)wr[l] - wl[l], wr[l] - dxa);
l = 1,r = n;
while (l <= r) {
int mid = (l + r) >> 1;
if (wl[mid] < dxb - zero) l = mid + 1;
else r = mid - 1;
}
R = sum[n] - sum[r - 1];
R -= min((double)wr[r] - wl[r], dxb - wl[r]);
ans = 1.0 * len * (sum[n] - R - L) / (dxb - dxa);
printf("%.15f",ans);
ch;
}
return 0;
}
Rain of Fire
不是杭师大是被codeforces拉黑了吗,今天做了两道codeforces的题,但是codeforces可以登上去的时间只有一个小时不到,到底什么时候可以交啊!
代码写了,样例叶过了,但是没办法提交不知道对不对,交了之后再贴上来
好好好过了过了过了,现在每次都争分多秒交 \(codeforces\)
#include<bits/stdc++.h>
#define kg putchar(' ')
#define ch puts("")
#define wj puts("-1")
#define se second
#define fi first
using namespace std;
typedef long long lwl;
typedef pair<int,int> pii;
const int N = 1e3 + 5, inf = 0x3f3f3f3f;
int n;
pii w[N];
map<pii,int> flag;
int h[N];
int id[5];
int a;
lwl fr(){
lwl x = 0, flag = 1;
char t;
t = getchar();
while (t < 48 || t > 57){
if (t == '-') flag = -1;
t = getchar();
}
while (t >= 48 && t <= 57){
x = x * 10 + t - 48;
t = getchar();
}
return x*flag;
}
void fw(lwl x){
if (x < 0) putchar('-'),x = -x;
if (x > 9){
fw(x / 10);
}
putchar(x % 10 + '0');
return ;
}
int min(int a,int b){
if (a > b) return b;
return a;
}
int max(int a,int b){
if (a < b) return b;
return a;
}
int dis(int i,int j) {
return max(abs(w[i].fi- w[j].fi),abs(w[i].se - w[j].se));
}
int find(int x) {
if (h[x] != x) h[x] = find(h[x]);
return h[x];
}
bool check(int k) {
for (int i = 1; i <= n; i ++) {
h[i] = i;
}
for (int i = 1; i <= n; i ++) {
for (int j = 1; j < i; j ++) {
if (w[i].fi != w[j].fi && w[i].se != w[j].se)
continue;
if (dis(i,j) > k) continue;
int ha = find(i),hb = find(j);
if (ha != hb) {
h[ha] = hb;
}
}
}
int cnt = 0;
for (int i = 1; i <= n; i ++) {
if (i == find(i)) {
cnt ++;
id[cnt] = i;
}
}
if (cnt == 1) return true;
if (cnt > 4) return false;
if (cnt == 2) {
for (int i = 1; i <= n; i ++) {
for (int j = 1; j < i; j ++) {
if (find(i) == find(j)) continue;
if (dis(i,j) <= k)
return true;
if (w[i].se == w[j].se &&
abs(w[i].fi - w[j].fi) <= 2 * k)
return true;
if (w[i].fi == w[j].fi &&
abs(w[i].se - w[j].se) <= 2 * k)
return true;
}
}
return false;
}
if (cnt == 3) {
int u[4] = {0,1,2,3};
for (int qwq = 1; qwq <= 3; qwq ++) {
swap(u[1],u[qwq]);
a ++;
for (int i = 1; i <= n; i ++) {
if (find(i) != id[u[1]]) continue;
for (int j = 1; j <= n ; j ++) {
if (find(j) != id[u[2]]) continue;
if (dis(i,j) <= k) {
flag[{w[i].fi,w[j].se}] = a;
flag[{w[j].fi,w[i].se}] = a;
}
}
}
for (int i = 1; i <= n; i ++) {
if (find(i) != id[u[1]]) continue;
for (int j = 1; j <= n; j ++) {
if (find(j) != id[u[3]]) continue;
if (dis(i,j) > k) continue;
if (flag[{w[i].fi,w[j].se}] == a ||
flag[{w[j].fi,w[i].se}] == a)
return true;
}
}
}
return false;
}
if (cnt == 4) {
int u[5] = {0,1,2,3,4};
for (int qwq = 1; qwq <= 2; qwq ++) {
a ++;
swap(u[2],u[3]);
for (int i = 1; i <= n; i ++) {
if (find(i) != id[u[1]]) continue;
for (int j = 1; j <= n; j ++) {
if (find(j) != id[u[2]]) continue;
if (dis(i,j) <= k) {
flag[{w[i].fi,w[j].se}] = a;
flag[{w[j].fi,w[i].se}] = a;
}
}
}
for (int i = 1; i <= n; i ++) {
if (find(i) != id[u[3]]) continue;
for (int j = 1; j <= n; j ++) {
if (find(j) != id[u[4]]) continue;
if (dis(i,j) > k) continue;
if (flag[{w[i].fi,w[j].se}] == a ||
flag[{w[j].fi,w[i].se}] == a)
return true;
}
}
}
return false;
}
return false;
}
int main(){
n = fr();
for (int i = 1; i <= n; i ++) {
w[i].fi = fr();
w[i].se = fr();
}
for (int i = 1; i <= n; i ++) {
h[i] = i;
}
int cnt = n;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j < i; j ++) {
if (w[i].fi != w[j].fi && w[i].se != w[j].se)
continue;
int ha = find(i),hb = find(j);
if (ha != hb) {
cnt --;
h[ha] = hb;
}
}
}
if (cnt > 2) {
wj;
return 0;
}
int l = 0,r = 2e9 + 1;
while (l <= r) {
int mid = ((lwl)l + r) / 2;
if (check(mid)) r = mid - 1;
else l = mid + 1;
}
fw(l);
return 0;
}
练习
三道二分,真是二分复建练习。考的时候只做了两道,还有一道是看了 Richard_H 之后写的,最后一题骗分骗了7分
今天有自己的笔记本可以登QQ,群里聊天聊飞了。最后一题太长了而且也没有什么时间看了,就输出了个样例然后随便输了个数,有七分的高分!
A.奇怪的矩阵
因为询问的时候都是以列作为单位的,所以说一开始先将所有数排序并且去重,我用的是 \(set\) ,因为不太习惯用 \(unique\)
然后算这个去重完的数组差分,也就是相邻的两个数之间的距离,也就是说这两个数经过一段距离后数字会重合。然后再对差分数组排个序,最后对这个差分数组求个前缀和,这样后面直接用就可以了。这里的前缀和就是如果距离超过了当前的差分值,那么这些行提供的贡献就是固定的 \(sum\) 值
最后对于每次询问,都把它转化成区间形式,因为这个区间左右移动时,中间的不同的数的数量是不会变的。然后对于这个区间二分一下当前区间在差分数组的哪个位置,这里的二分就相当于手写 \(lowerbound\)
最后再针对没有完全包括的区间单独算一下就可以了。
#include<bits/stdc++.h>
#define kg putchar(' ')
#define ch puts("")
using namespace std;
typedef long long lwl;
const int N = 1e5 + 5, inf = 0x3f3f3f3f;
const lwl m = 1e18;
int n;
lwl w[N];
map<lwl,lwl> h;
lwl cf[N];
lwl sum[N];
lwl fr(){
lwl x = 0, flag = 1;
char t;
t = getchar();
while (t < 48 || t > 57){
if (t == '-') flag = -1;
t = getchar();
}
while (t >= 48 && t <= 57){
x = x * 10 + t - 48;
t = getchar();
}
return x*flag;
}
void fw(lwl x){
if (x < 0) putchar('-'),x = -x;
if (x > 9){
fw(x / 10);
}
putchar(x % 10 + '0');
return ;
}
int main(){
freopen("qwq.in","r",stdin);
set<int> s;
n = fr();
for (int i = 1; i <= n; i ++) {
s.insert(fr());
}
n = s.size();
int idx = 0;
for (auto i : s) {
w[++ idx] = i;
}
for (int i = 1; i < n; i ++) {
cf[i] = w[i + 1] - w[i];
}
sort(cf + 1,cf + n);
for (int i = 1; i <= n; i ++) {
sum[i] = sum[i - 1] + cf[i];
}
int Q = fr();
while (Q --) {
lwl l = fr(),r = fr();
lwl y = r - l + 1;
l = 1,r = idx;
while (l <= r) {
lwl mid = (l + r) >> 1;
if (cf[mid] < y) l = mid + 1;
else r = mid - 1;
}
if (r == n) r = n - 1;
lwl ans = (n - r) * y + sum[r];
fw(ans);
ch;
}
return 0;
}
B.区间加法
考虑贪心加二分。二分就是二分答案,然后这里二分答案的时候不能直接用 \(1e14\) ,不然会 \(TLE\) ,因为这里给的范围是 \(\sum\) ,所以我们对每一组数据都求一遍最大值。
在 \(check\) 函数里面,求当前答案是否符合的时候,这里用的是树状数组,但是复杂度好像有点问题,可以直接标记用前缀和做,但还我懒得写了,如果改做法可以省掉一个 \(\log n\)
但是这一题的数据好像不是很强,如果最大值取 \(1e8\) 都可以做,真是让人大吃一惊。
#include<bits/stdc++.h>
#define kg putchar(' ')
#define ch puts("")
#define wj puts("-1")
#define se second
#define fi first
using namespace std;
typedef long long lwl;
typedef pair<int,int> pii;
const int N = 2e5 + 100, inf = 0x3f3f3f3f;
priority_queue<int> q;
int n,m,k,b;
lwl w[N];
pii qj[N];
lwl tr[N];
lwl fr(){
lwl x = 0, flag = 1;
char t;
t = getchar();
while (t < 48 || t > 57){
if (t == '-') flag = -1;
t = getchar();
}
while (t >= 48 && t <= 57){
x = x * 10 + t - 48;
t = getchar();
}
return x*flag;
}
void fw(lwl x){
if (x < 0) putchar('-'),x = -x;
if (x > 9){
fw(x / 10);
}
putchar(x % 10 + '0');
return ;
}
lwl lowbit(lwl a) {
return a & -a;
}
void add(int x,lwl k) {
while (x <= n + 1) {
tr[x] += k;
x += lowbit(x);
}
}
lwl sum(int x) {
lwl ans = 0;
while (x) {
ans += tr[x];
x -= lowbit(x);
}
return ans;
}
void change(int l,int r) {
add(l,b);
add(r + 1,-b);
}
bool check(lwl mid) {
while (q.size()) q.pop();
memset(tr,0,sizeof tr);
queue<int> qq;
for (int i = 1; i <= n; i ++) {
if (w[i] < mid) qq.push(i);
}
int cnt = 0;
int u = 1;
while (qq.size()) {
auto t = qq.front();
qq.pop();
while (u <= m && qj[u].fi <= t) {
q.push(qj[u].se);
u ++;
}
while (w[t] + sum(t) < mid) {
cnt ++;
if (cnt > k) return false;
if (!q.size()) return false;
auto tt = q.top();
q.pop();
change(t,tt);
}
}
return true;
}
int main(){
//freopen("qwq.in","r",stdin);
int T = fr();
while (T --) {
n = fr(),m = fr(),k = fr(),b = fr();
for (int i = 1; i <= n; i ++) {
w[i] = fr();
}
for (int i = 1; i <= m; i ++) {
qj[i].fi = fr();
qj[i].se = fr();
}
sort(qj + 1,qj + 1 + m);
lwl l = 0,r = 1e9;
while (l <= r) {
lwl mid = (l + r) >> 1;
if (check(mid)) l = mid + 1;
else r = mid - 1;
}
fw(r);
ch;
}
return 0;
}
标签:二分,fr,return,int,mid,lwl,define
From: https://www.cnblogs.com/jingyu0929/p/17545621.html