二分法に関するいくつかの結論
二分探索
[次のプログラムはすべて、区間[l、r]でxを検索し、デフォルトのデータ順序は減少しません]
1.二分探索間隔での数値の添え字
二分探索間隔(存在し、一意)内の数値の添え字が存在しない場合は、-1を返します。
int search(int l,int r,int x)
{
int mid;
while (l<=r)
{
mid=(l+r)>>1;
if(a[mid]==x) return mid;
if(a[mid]<x) l=mid+1;
else r=mid-1;
}
return -1;
}
これは最もよく書かれた二分法でなければなりません
2.クエリ間隔での<=xの最大値
間隔内の<=xの最大値を照会します(複数の最大値がある場合は、右端の座標を返します)。
int search(int l,int r,int x)
{
int mid;
while (l<r)
{
mid=(l+r+1)>>1;
if(a[mid]<=x) l=mid;
else r=mid-1;
}
return l;
}
2点プロセスについてはあまり言うことはありませんが、2点に注意してください。
- [l、r]でクエリを実行する場合、渡される推奨パラメーターはl-1.rです。したがって、戻り値がl-1の場合、値<= xがないことを意味します。つまり、 2つのポイントの前に判断することを選択できます。解決策が存在すると判断されたら、再度分割します。
- mid =(l + r)>>1の代わりにmid=(l + r + 1)>> 1後者の方法を採用する場合、間隔が2、3、次にmid = 2に短縮されたとすると、 [mid] <= xが確立され、次にl = midが確立されます。これは無限ループになるため、+1は2で除算されます。
3.クエリ間隔の>=xの最小値
間隔内の最小値>=xを照会します(複数の最小値がある場合は左端の座標を返します)。
int search(int l,int r,int x)
{
int mid;
while (l<r)
{
mid=(l+r)>>1;
if(a[mid]>=x) r=mid;
else l=mid+1;
}
return l;
}
条件がr=midおよびl=mid + 1になっただけなので、midをmid =(l + r)>> 1に変更する必要があります。そうしないと、無限ループになります。クエリ間隔[l、r]はパラメータl、r + 1として渡され、戻り値は解がないためr+1です。
このように、上限と下限、および中間を取る条件が適切に制御されている限り、2つに分けることができます。
4.実数を除算します
実数の二分法は書きやすいです。トピックに必要な精度に従って境界を制御するだけです。通常、無限ループはありません。
while (fabs(r-l)>EPS)//EPS是题目要求的精度
{
mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
5、練習用の質問
1.ネットワークケーブルスーパーバイザー
トピックの説明と入力および出力
入出力:
输入:
4 11
8.02
7.43
4.57
5.39
输出:
2.00
トピックのアイデアとコード
アイデア:これは、2つのポイントに直接分割して、結果と一致するかどうかを判断することです。!!特殊な場合、つまり分割できない場合に注意して判断してください。
コード:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+10;
const ll maxm=1e8+10;
const ll mod=1e9+7;
ll n,m;
ll a[maxn];
ll mx;
ll check(ll x){
ll res=0;
for(int i=1;i<=n;i++){
res+=a[i]/x;
}
return res;
}
int main(){
cin>>n>>m;
ll sum=0;
for(int i=1;i<=n;i++){
double s;
cin>>s;
a[i]=s*100;
mx=max(a[i],mx);
sum+=a[i];
}
if(m>sum){
printf("0.00");
return 0;
}
ll l=1,r=mx;
ll ans=0;
while(l<r){
ll mid=(l+r+1)>>1;
if(check(mid)>=m){
l=mid;
}
else{
r=mid-1;
}
}
printf("%.2lf",l*1.0/100);
return 0;
}
2.教室を借りる
トピックの説明と入力および出力
入出力:
输入:
4 3
2 5 4 3
2 1 3
3 2 4
4 2 4
输出:
-1
2
トピックのアイデアとコード
アイデア: 1つ目は区間の修正です。ここでは、差を使用して問題を解決し、結果の区間を二分法で狭めます。!!
二分コードと差動コード
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+10;
const ll maxm=1e8+10;
const ll mod=1e9+7;
int line[1000010], l[1000010], r[1000010], d[1000010], change[1000010],sum[1000010];
int n,m;
int check(int x)
{
memset(change,0,sizeof(change));
for (int i = 1; i <= x; i++)
{
change[l[i]]+=d[i];
change[r[i]+1]-=d[i];
}
for (int i = 1; i <= n; i++)
sum[i]=sum[i-1]+change[i];
//obj 2抹平差分数组
for (int i = 1; i <= n; i++)
if(sum[i]>line[i])return false;
//obj 3什么情况下是发生了问题?
return true;
}
int main(){
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &line[i]);
for (int i = 1; i <= m; i++)
scanf("%d %d %d", &d[i], &l[i], &r[i]);
if(check(n))
{
printf("0");
return 0;
}
int l = 1, r = n, mid=0;
while(l<r)
{
mid = (l + r) >> 1;
if(!check(mid))//obj 5
r=mid;
else
l=mid+1;
//cout<<l<<" "<<r<<" "<<check(mid)<<endl;
}
printf("-1\n");
printf("%d", l);
return 0;
}
ツリー配列コード:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll maxn=1e5+10;
const ll maxm=1e8+10;
const ll mod=1e9+7;
int line[1000010], l[1000010], r[1000010], d[1000010], t[1000010],ti[1000010];
int n,m;
int lowbit(int n){
return n&(-n);
}
void update(int x,int val){
for(int i=x;i<=n;i+=lowbit(i)){
t[i]+=val;
ti[i]+=val*x;
}
}
int getsum(int x){
int sum=0;
for(int i=x;i;i-=lowbit(i)){
sum+=(x+1)*t[i]-ti[i];
}
return sum;
}
int pan(){
int ans=0;
for(int i=1;i<=n;i++){
int sum=getsum(i)-getsum(i-1);
if(sum>line[i])return 0;
}
return 1;
}
int main(){
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &line[i]);
int f=0;
for (int i = 1; i <= m; i++)
{
scanf("%d %d %d", &d[i], &l[i], &r[i]);
update(l[i],d[i]);
update(r[i]+1,-d[i]);
if(f)continue;
if(!pan()){
f=i;
}
}
if(f)printf("-1\n%lld",f);
else{
printf("0");
}
return 0;
}
6、みんなへの推薦の段落
「未定の場合は春のそよ風に聞いてみてください。春のそよ風が話せない場合は心に従います」とは、何かに躊躇している場合は、春のそよ風にどうやってやるのか聞いてみてください。「未定の場合は春のそよ風を聞くことができます。春のそよ風が話せない場合は心に従います。」この文章はインターネット作家「風水オペラ王子」が書いた「建来」からのものです。原文は、「未定の場合は、春のそよ風を聞くことができます。あなたの心に従ってください」です。