基础分治总结

基础分治总结

前记:边敲代码边写博客,本专题完成速度取决于敲代码过题速度(好像没啥写的,就写四个意思一下吧)。分治,其目的在于将一个大问题分解成很多小问题,依次求得其解,而得到最终答案。

【分治】金块问题

题目描述:
一个老板有一袋金块,里面有n块金子。每个月,老板会从袋子中拿出两个金块奖励两名期雇员。按规矩,最优秀的雇员将得到袋中最重的金块,排名第二的雇员将得到袋中最轻的金块。周期性地往袋中加入新的金块,那么每个月他都要找出最重和最轻的金块。假设有一台比较质量的仪器,我们希望用尽量少的比较次数找出最重和最轻的金块。
输入:
第1行只有一个整数n(2≤n≤100000)。
第2行n个长整型范围内的整数,每个整数之间用一个空格隔开,表示每块金子的质量。
输出:
输出两个用空格分开的整数,表示最重和最轻的金块的质量。
样例输入:
8
10 8 2 4 5 3 9 1
样例输出:
10 1
题目原意应该是要用二分。。但是数据这么水,暴力完全可以过。

#include <stdio.h>
#include <stdlib.h>
#define N 1000000
int main()
{
    long int n,a[N];
    long int i,max=0,min=100000;
    scanf("%ld",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%ld",&a[i]);
        if(a[i]>max) max=a[i];
        if(a[i]<min) min=a[i];
    }
    printf("%ld %ld\n",max,min);
    return 0;
}

【分治】桐桐查单词

题目描述:
今天桐桐接到一个任务,就是要把一篇英语文章翻译成中文。对桐桐来说这任务实在太艰巨的桐桐只好拿着英文字典,一句句慢慢翻译起来。希望桐桐能在规定的时间内完成吧。
输入:
第1行一个整数N,表示字典中一共有多少单词(N≤20000)。

接下来每两行表示一个单词,其中:

第1行是一个长度≤100的字符串,表示这个单词,全部字母小写,单词不会重复。

第2行是一个整数,表示这个单词在字典中的页码。

接下来一行是一个整数W,表示要查的单词数(M≤10000)。

接下来M行,每行一个字符串,表示要查的单词,保证在字典中存在。
输出 :
M行,每行一个整数,表示第i个单词在字典中的页数。
样例输入:
2
scan
10
word
15
2
scan
word
样例输出:
10
15
map映射,直接搞定。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
map<string,int>mapp;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        string str;
        cin>>str;
        int num;
        scanf("%d",&num);
        mapp[str]=num;
    }
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        string str;
        cin>>str;
        printf("%d\n",mapp[str]);
    }
    return 0;
}

【分治】化装晚会

题目描述:
万圣节又到了!FJ打算带他的奶牛去参加化装晚会,但是,FJ只做了一套能容下两头总长不超过S (1≤S≤1000000)的奶牛恐怖服装。FJ养了N(2≤N≤20000)头按1–N顺序编号的奶牛,编号为i的奶牛的长度为L_i(1≤L_i≤1000000)。如果两头奶牛的总长度不超过S,那么她们就能穿下这套服装。
FJ想知道,如果他想选择两头不同的奶牛来穿这套衣服,一共有多少种满足条件的方案。
输入:
第1行是2个整数:N和S;
第2~N+l行每行一个整数:L_i。
输出:
1个整数,表示FJ可选择的所有方案数。注意奶牛顺序不同的两种方案是被视为相同的。
样例输入:
4 6
3
5
2
1
样例输出:
4
先从小到大排序,然后从第一个开始,只搜其后的,有几个能穿上就加几,但肯定不能一个一个搜啊,所以,二分就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[20005];
int erfen(int start,int endd,int l)
{
    int mid=(start+endd)/2;
    if((a[mid]<=l&&a[mid+1]>l)||(mid==endd&&a[mid]<=l))
        return mid;
    else if(a[mid]<=l)
        return erfen(mid+1,endd,l);
    else if(a[mid]>l)
    {
        if(start!=mid)
            return erfen(start,mid,l);
        else
            return start-1;//二分时要注意这种特殊情况,搜索不到要返回start-1
    }
}
int main()
{
    int n,l;
    int ans=0;
    scanf("%d%d",&n,&l);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    sort(a+1,a+1+n);
    for(int i=1;i<n;i++)
    {
        ans+=(erfen(i+1,n,l-a[i])-i);
    }
    printf("%d\n",ans);
    return 0;
}

【分治】珍珠项链

题目描述:
我有很多(n条)珍珠项链,每天我都要从中挑一条戴上……挑哪条很有讲究,不能太难看也不能太好看。所以我希望你能帮帮我,解决这个问题――每天帮我算算,那天我能戴的项链有多少条。
输入:
第1行为正整数n,表示项链的总条数(n≤100000);
第2行有n个整数(代表每条项链晶的好看程度Xi,0≤Xi≤maxlongint);
第3行为正整数m,表示总天数(也就是总询问次数,其中m≤100000);
以下m行,每行两个整数Ai,Bi(1≤Ai,Bi≤maxlongint),询问好看程度在Ai到Bi之间的项链条数(含等于Ai或Bi的,Ai与Bi大小关系不确定)。
输出:
输出m行,对于每次询问输出一行,从Ai到Bi(含Ai,Bi)好看程度在Ai到Bi之间的项链条数。
样例输入:
7
8 2 3 5 6 7 7
6
1 5
8 6
1 10
5 5
4 4
7 8
样例输出:
3
4
7
1
0
3
把上面那个题稍微改一下就行了,上面那个是<=,这道题多判断一个<,即加一种二分。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100005];
int erfen(int start,int endd,int l)
{
    int mid=(start+endd)/2;
    if((a[mid]<=l&&a[mid+1]>l)||(mid==endd&&a[mid]<=l))
        return mid;
    else if(a[mid]<=l)
        return erfen(mid+1,endd,l);
    else if(a[mid]>l)
    {
        if(start!=mid)
            return erfen(start,mid,l);
        else
            return start-1;
    }
}
int erfen1(int start,int endd,int l)
{
    int mid=(start+endd)/2;
    if((a[mid]<l&&a[mid+1]>=l)||(mid==endd&&a[mid]<l))
        return mid;
    else if(a[mid]<l)
        return erfen1(mid+1,endd,l);
    else if(a[mid]>=l)
    {
        if(start!=mid)
            return erfen1(start,mid,l);
        else
            return start-1;
    }
}
int main()
{
    int n;
    int ans=0;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%lld",&a[i]);
    }
    sort(a+1,a+1+n);
    int m;
    scanf("%d",&m);
    while(m--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if(x>y)
        {
            x^=y;
            y^=x;
            x^=y;
        }
        ans=erfen(1,n,y)-erfen1(1,n,x);
        printf("%d\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值