【一本通基础+提高】二分、三分与分治做题记录
【一本通基础】分治算法做题记录
Problem A
Problem B
Problem C
Problem D
Problem E
Problem F
Problem G
Problem H
Problem I
Problem J
Problem K
Problem L
- 实数二分。注意 \(eps\) 的值(也就是误差)。二分分段的网线的长度。千万要注意是实数二分!要用 \(double\) !!
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,k;
double a[101010];
double l = 0,r,eps = 1e-5;
bool check(double mid){
int ans = 0;
for(int i = 1;i <= n;i++){
ans+=(a[i]/mid);
}
return ans>= k;
}
int main(){
cin>>n>>k;
for(int i = 1;i <= n;i++){
cin>>a[i];
r += a[i];
}
while(r-l > eps){
double mid = (l+r)/2.0;
if(check(mid)){
l = mid;
}else r = mid;
}
if(r < 0.01) r = 0.00;
cout<<fixed<<setprecision(2)<<floor(r*100.0)/100.00;
}
Problem M
- 二分答案。二分最大值,如果可以满足就将该值增大,否则就将该值减小。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int a[1010100];
int n,l = INT_MAX,r,m;
bool check(int mid){
int now = 0;
int ans = 1;
for(int i = 1;i <= n;i++){
if(a[i] > mid) return false;
if(a[i]+now > mid){
now = a[i];
ans++;
}else now += a[i];
}
return ans <= m;
}
int main(){
cin>>n>>m;
for(int i = 1;i <= n;i++){
cin>>a[i];
r += a[i];
l = min(l,a[i]);
}
while(l <= r){
int mid = l+r>>1;
if(check(mid)){
r = mid-1;
}else{
l = mid+1;
}
}
cout<<l<<endl;
}
Problem N
- 不是二分。双指针例题。这里蒟蒻使用 \(map\) 解决。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
map <int,int> mp;
int n;
int a[101010];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin>>a[i];
mp[a[i]]++;
}
int k;
cin>>k;
bool f = false;
int x = 0,y = 0,z = INT_MAX;
for(int i = 1;i <= n;i++){
if(mp[k-a[i]] > 0) {
f = 1;
if(z > min(a[i],k-a[i])){
z = min(a[i],k-a[i]);
y = max(a[i],k-a[i]);
x = min(a[i],k-a[i]);
}
}
}
if(f == 0 or (x == 1 and y == 1)) puts("No");
else{
cout<<x<<" "<<y;
}
}
Problem O
- 根本就不是分治。先把整个数列排序(\(sort\)),然后再去重(\(unique\))。就得到答案了。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int a[1010101];
int n;
int main(){
cin>>n;
for(int i = 1;i <= n;i++){
cin>>a[i];
}
sort(a+1,a+1+n);
n = unique(a+1,a+1+n)-a-1;
for(int i = 1;i <= n;i++){
cout<<a[i]<<" ";
}
}
Problem P
Problem Q
- 二分答案:直接二分最长跳跃距离,如果能够满足条件,就增加跳跃距离,否则就减小跳跃距离。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int L,n,m;
int a[2101010];
int ans;
inline bool check(int mid){
int times = 0,ip = 0;
for(int i = 1;i <= n+1;i++){
if(a[i]-a[ip] < mid){
times++;
if(times > m) return false;
}else ip = i;
}
return times <= m;
}
int main(){
cin>>L>>n>>m;
a[n+1] = L;
int l = 1,r = L;
for(int i = 1;i <= n;i++){
cin>>a[i];
l = min(l,a[i]-a[i-1]);
}
l = min(l,L-a[n]);
while(l <= r){
int mid = l+r>>1;
if(check(mid)){
l = mid+1;
}else r = mid-1;
}
cout<<l-1<<endl;
return 0;
}
【提高篇】二分与三分做题记录
Problem A
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[2101010];
int ans;
inline bool check(int mid){
int dis = a[1],mm = 1;
for(int i = 2;i <= n;i++){
if(a[i]-dis >= mid){
mm++;
dis = a[i];
}
}
return mm >= m;
}
int main(){
cin>>n>>m;
int l = 1,r = -99;
for(int i = 1;i <= n;i++){
cin>>a[i];
}
sort(a+1,a+1+n);
for(int i = 1;i <= n;i++){
l = min(l,a[i]-a[i-1]);
}
r = a[n]-a[1];
while(l <= r){
int mid = l+r>>1;
if(check(mid)){
l = mid+1;
}else r = mid-1;
}
cout<<l-1<<endl;
return 0;
}
Problem B
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int a[101010],n,L;
double b[101010];
int main(){
cin>>n;
cin>>L;
int maxx = 0;
for(int i = 1;i <= n;i++) cin>>a[i],maxx = max(maxx,a[i]);
double l = 0,r = maxx*1.0,mid;
while(r-l > 1e-5){
mid = (l+r)/2;
for(int i = 1;i <= n;i++)
b[i] = (b[i-1]+a[i]*1.0-mid)*1.0;
double ans = 0;
bool fl = 0;
for(int i = L;i <= n;i++){
ans = min(ans,b[i-L]);
if(b[i]-ans >= 0.0){
fl = 1;
break;
}
}
if(fl == 1) l = mid;
else r = mid;
}
cout<<(int)(r*1000)<<endl;
}
Problem C
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n;
double a[101010],b[101010],c[101010];
double f(double x){
double mx = -1e9;
for(int i = 1;i <= n;i++) mx = max(mx,a[i]*x*x+b[i]*x+c[i]);
return mx;
}
int main(){
int T;
cin>>T;
while(T--){
scanf("%d",&n);
for(int i = 1;i <= n;i++) scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
double l = 0,r = 1000;
while(r-l>1e-11){
double m1 = l+(r-l)/3,m2 = r-(r-l)/3;
if(f(m1) <= f(m2)) r = m2;
else l = m1;
}
printf("%.4lf\n",f(r));
}
}
Problem D
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,l = INT_MIN,r,m;
int a[1010001];
inline bool check(int mid){
int tot = 0;
int times = 1;
for(int i = 1;i <= n;i++){
if(tot+a[i] <= mid) tot += a[i];
else tot = a[i],times++;
}
return times <= m;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
l = max(l,a[i]);
r += a[i];
}
while(l <= r){
int mid = l+r>>1;
if(check(mid)) r = mid-1;
else l = mid+1;
}
cout<<l<<endl;
return 0;
}
Problem E
点击查看代码
#include <bits/stdc++.h>
using namespace std;
struct node{
int x,y;
}a[1010101];
int f[1010101][2];
int n;
int find(int x){
if(f[x][0] != x) return f[x][0] = find(f[x][0]);
return x;
}
void merge(int x,int y){
f[find(x)][0] = f[find(y)][0];
f[find(y)][1] += f[find(x)][1];
}
bool check(int x){
for(int i = 1;i <= n;i++){
for(int j = i+1;j <= n;j++){
if(abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y) <= x*2 and find(i) != find(j)) merge(i,j);
}
}
int k = find(1);
for(int i = 2;i <= n;i++){
if(find(i) != k) return false;
}
return true;
}
int main(){
cin>>n;
for(int i = 1;i <= n;i++){
cin>>a[i].x>>a[i].y;
}
int l = 0,r = 1e9;
while(l <= r){
for(int i = 1;i <= n;i++) f[i][0] = i,f[i][1] = 1;
int mid = l+r>>1;
if(check(mid)) r = mid-1;
else l = mid+1;
}
cout<<l<<endl;
}
Problem F
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int t;
double hb,h,d;
double f(double x){
double l = hb-(d*(hb-h)/x);
return d-x+l;
}
int main(){
cin>>t;
while(t--){
cin>>hb>>h>>d;
double l = d-(h*d/hb),r = d;
while(r-l >= 1e-5){
double m1 = l+(r-l)/3,m2 = r-(r-l)/3;
if(f(m1) < f(m2)) l = m1;
else r = m2;
}
printf("%.3lf\n",f(r));
}
}
Problem G
- 三分套三分。分别在 \(AB\) 和 \(CD\) 上找两个满足条件的点。
#include<bits/stdc++.h>
#define eps 1e-6
using namespace std;
int P,Q,R;
struct node{double x,y;}A,B,C,D,a,b;
double dis(node a,node b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double cal(double p1,double p2) {
a.x=A.x+(B.x-A.x)*p1;
a.y=A.y+(B.y-A.y)*p1;
b.x=C.x+(D.x-C.x)*p2;
b.y=C.y+(D.y-C.y)*p2;
return dis(A,a)/P+dis(a,b)/R+dis(b,D)/Q;
}
double get(double x) {
double l=0,r=1;
while(r-l>eps) {
double M1=l+(r-l)/3.0,M2=r-(r-l)/3.0;
if(cal(x,M1)>cal(x,M2)) l=M1; else r=M2;
}
return cal(x,l);
}
int main() {
cin>>A.x>>A.y>>B.x>>B.y;
cin>>C.x>>C.y>>D.x>>D.y;
cin>>P>>Q>>R;
double l=0,r=1;
while(r-l>eps) {
double M1=l+(r-l)/3.0,M2=r-(r-l)/3.0;
if(get(M1)>get(M2)) l=M1; else r=M2;
}
printf("%.2lf",get(l));
}
//三分(a点)套三分(b点)