今天晚自习机房刷题,有一道题最终WA掉两组,极其不爽,晚上回家补完作业欣然搞定它,特意来写篇博文来记录下

(最想吐槽的是这个叫做分治的分类,里面的题目真的需要分治吗。。。)

先来说下分治法

分治法的设计思想是:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。

三、分治法适用的情况

分治法所能解决的问题一般具有以下几个特征:

1) 该问题的规模缩小到一定的程度就可以容易地解决

2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。

3) 利用该问题分解出的子问题的解可以合并为该问题的解;

4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;

第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;、

第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。

第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。

依据分治法设计程序时的思维过程

实际上就是类似于数学归纳法,找到解决本问题的求解方程公式,然后根据方程公式设计递归程序。

1、一定是先找到最小问题规模时的求解方法

2、然后考虑随着问题规模增大时的求解方法

3、找到求解的递归函数式后(各种规模或因子),设计递归程序即可。

网上和书上学了下,然而你丫做题基本用不大着,也是令我非常无奈

下面是题目。。。。

一、输出前k大的数

7617:输出前k大的数

总时间限制: 10000ms 单个测试点时间限制: 1000ms 内存限制: 65536kB

描述

给定一个数组,统计前k大的数并且把这k个数从大到小输出。

输入

第一行包含一个整数n,表示数组的大小。n < 100000。

第二行包含n个整数,表示数组的元素,整数之间以一个空格分开。每个整数的绝对值不超过100000000。

第三行包含一个整数k。k < n。

输出

从大到小输出前k大的数,每个数一行。

样例输入

10

4 5 6 9 8 7 1 2 3 0

5

样例输出

9

8

7

6

5

然而此题略蛋疼,表示C++党一个sort轻松+愉快

于是就有代码。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[100000]={0};
int main()
{
int n,m;
cin>>n;
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
cin>>m;
for (int i=n;i>=n-m+1;i--)
cout<<a[i]<<endl;
//printf("%d ",&a[i]);
return 0;
}

此题不解释

二、区间合并

这个题好像排序也解决了。。。表示我不禁想吐槽了

代码(这个题一开始智商被压制了。。。有点略蠢)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct data{
int head,tail;
};
data qj[50010]={0};
int cmp(data x,data y)
{
if (x.head<y.head)
return 1;
else
if (x.head==y.head)
if (x.tail<=y.tail)
return 1;
else
return 0;
else
return 0;
} int main()
{
int n;
bool f=false;
int start=0,end=0;//如果可以合并,开头和结尾
scanf("%d",&n);
int i,j;
for (i=1;i<=n;i++)
{
scanf("%d%d",&qj[i].head,&qj[i].tail);
end=max(end,qj[i].tail);//表示结尾的取所有区间的结尾的最大值
}
sort(qj+1,qj+n+1,cmp);//按照区间的开头进行排序,从小到大,一样则结尾从小到大排序
start=qj[1].head;//表示开头的为最小的那个
int h=qj[1].head,t=qj[1].tail;//为下文判断是否可以合并做准备
for (i=2;i<=n;i++)
if (qj[i].head>t)//因为有序,满足这个就不能合并
{f=true;break;}
else
t=max(t,qj[i].tail); //两个合并后,把当前最大的结尾记录,为以后对比做铺垫
if (!f)
printf("%d %d",start,end);
else
printf("no");
return 0;
}

三、求排列的逆序数

逆序数,及排列中的逆序对的个数,此处用的归并排序,对归并排序进行一个计数的操作即可实现(终于正常的用了次分治,着实不易啊)

7622:求排列的逆序数

总时间限制: 1000ms 内存限制: 65536kB

描述

在Internet上的搜索引擎经常需要对信息进行比较,比如可以通过某个人对一些事物的排名来估计他(或她)对各种不同信息的兴趣,从而实现个性化的服务。

对于不同的排名结果可以用逆序来评价它们之间的差异。考虑1,2,…,n的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序。

一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。显然,由1,2,…,n 构成的所有n!个排列中,最小的逆序数是0,对应的排列就是1,2,…,n;最大的逆序数是n(n-1)/2,对应的排列就是n,(n-1),…,2,1。逆序数越大的排列与原始排列的差异度就越大。

现给定1,2,…,n的一个排列,求它的逆序数。

输入

第一行是一个整数n,表示该排列有n个数(n <= 100000)。

第二行是n个不同的正整数,之间以空格隔开,表示该排列。

输出

输出该排列的逆序数。

样例输入

6

2 6 3 4 5 1

样例输出

8

提示

1. 利用二分归并排序算法(分治);

2. 注意结果可能超过int的范围,需要用long long存储。

此处稍提一下归并排序

归并排序的基本思想

将待排序序列R[0…n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列。

综上可知:

归并排序其实要做两件事:

(1)“分解”——将序列每次折半划分。

(2)“合并”——将划分后的序列段两两合并后排序。

这道题在归并时记一个数就可以,具体的可以证明,但就不多提了

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int a[100010]={0},L[100010]={0},R[100010]={0};
long long ans=0;
#define M 1000000000; void gb(int left,int mid,int right)
{
int ll=mid-left+1;
int lr=right-mid;
for (int i=1;i<=ll;i++)
L[i]=a[left+i-1];//此操作方便处理
for (int i=1;i<=lr;i++)
R[i]=a[mid+i];
L[ll+1]=M;//将最后一个赋给一个极大值,可以当作一个“哨兵”非常的精妙,然而经测试似乎不加这条语句会出错
R[lr+1]=M;
int l=1,r=1;
for (int i=left; i<=right; i++)
{
if (L[l]<=R[r])
{
a[i]=L[l];
l++;
}
else
{
a[i]=R[r];
r++;
ans+=ll-l+1;//求逆序对的唯一多出来的语句
}
}
} void gbsort(int left,int right)
{
int mid=(left+right)/2;
if (left<right)
{
gbsort(left,mid);//不断分治
gbsort(mid+1,right);
gb(left,mid,right);
}
} int main()
{
int n;
scanf("%d",&n);
for (int i=1; i<=n; i++)
scanf("%d",&a[i]);
gbsort(1,n);
printf("%lld",ans);
return 0;
}

四、一元三次方程求解

然而第一眼看到这个题其实我是拒绝的,有想过用求根公式,然而本人数学并不是非常好(当然也不是很差)表示求根公式和数学求法非常神,表示理解还不如二分查找答案多编几行代码快,于是开始二分

PS:此处鸣谢聪哥的数学指引

7891:一元三次方程求解

总时间限制: 1000ms 内存限制: 65536kB

描述

有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程。

给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。

输入

一行,包含四个实数a,b,c,d,相邻两个数之间用单个空格隔开。

输出

一行,包含三个实数,为该方程的三个实根,按从小到大顺序排列,相邻两个数之间用单个空格隔开,精确到小数点后2位。

样例输入

1.0 -5.0 -4.0 20.0

样例输出

-2.00 2.00 5.00

提示

记方程f(x)=0,若存在2个数x1和x2,且x1(此处题目应该是残了。。。)(请无视)

闲话不多说上代码吧,这个题也没什么好扯的。。。

#include<cstdio>
#include<cmath>
using namespace std;
double a,b,c,d; double f(double x)
{
return a*x*x*x+b*x*x+c*x+d;
} double search(double left,double right)
{
double mid=(left+right)/2;
if (right-left<1e-4) return mid;
else
{
if (f(mid)==0) return mid;
else if (f(left)*f(mid)<0) return search(left,mid);
else return search(mid,right);
}
} int main()
{
double x1,x2;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
if (a<0)
{
a=-a;b=-b;c=-c;d=-d;
}
x1=(-2*b-sqrt(4*b*b-12*a*c))/(a*6);
x2=(-2*b+sqrt(4*b*b-12*a*c))/(a*6);
double ans1,ans2,ans3;
ans1=search(-101,x1);
ans2=search(x1,x2);
ans3=search(x2,101);
printf("%.2f %.2f %.2f",ans1,ans2,ans3);
return 0;
}

五、统计数字

第一眼看题,以为是随便一个桶排就出来了,后来一看数据范围就呵呵了,不过这个题着实还是不难,然而还没有离散化难呢,那怕个什么啊,水量仅次第一题的存在,排个序,统计个数一波输出,一波带走

然而我蛋神@tyc0520居然一开始不会编,表示莫名奇妙,先跪一发

7909:统计数字

总时间限制: 1000ms 内存限制: 65536kB

描述

某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*109)。已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出统计结果。

输入

包含n+1行:

第一行是整数n,表示自然数的个数;

第2~n+1每行一个自然数。

40%的数据满足:1<=n<=1000;

80%的数据满足:1<=n<=50000;

100%的数据满足:1<=n<=200000,每个数均不超过1500 000 000(1.5*10^9)。

输出

包含m行(m为n个自然数中不相同数的个数),按照自然数从小到大的顺序输出。每行输出两个整数,分别是自然数和该数出现的次数,其间用一个空格隔开。

样例输入

8

2

4

2

4

5

100

2

100

样例输出

2 3

4 2

5 1

100 2

下面是代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[200010]={0};
int main()
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
int sum=0;
for (int i=1;i<=n;i++)
{
sum++;
if (a[i]==a[i+1])
continue;
else
{
printf("%d %d\n",a[i],sum);
sum=0;
}
}
return 0;
}

好了,时间不早了,洗睡去了,表示前路漫漫,仍须努力啊

NOI题库分治算法刷题记录的更多相关文章

  1. 【托业】【全真题库】TEST01-03-阅读题

    [托业][全真题库]TEST01-03-阅读题

  2. leetcode 算法刷题(一)

    今天开始刷Leetcode上面的算法题.我会更新我刷题过程中提交的代码(成功和不成功的都有)和比较好的解法 第二题 Add Two Numbers 题目的意思:输入两个链表,这两个链表都是倒序的数字, ...

  3. 2019年Amazon AWS-Solutions-Architect-Professional考试最新题库(AWS SAP题库)带考试模拟器

    大家好,由于最近自己备考Amazon AWS-Solutions-Architect-Professional考试,购买了以下链接的题库,并通过了考试 https://www.kaoguti.gq/A ...

  4. php+mysql开发一个最简单的在线题库,在线做题系统!

    题库,对于教育机构,学校,在线教育,是很有必要的,网上也有不少的第三方在线题库系统,但是本次案例,会让有需要的人了解题库的开发思路,其实很简单,无非就是一个表单验证,数据库验证. 1.先构建表单数据2 ...

  5. leetcode算法刷题(三)

    今天在刷了几道简单的动态规划后,又看了看string方面的题 第五题 Longest Palindromic Substring 题目的意思:求一个字符串的最长回文子串 分析:开始,我的想法是,现在字 ...

  6. leetcode算法刷题(四)——动态规划(二)

    又到了晚上,动态规划,开刷! 第121题 Best Time to Buy and Sell Stock 题目的意思:给予一个数组price,表示特定股票在某天的股价,里面第i个数表示第i天的价格.只 ...

  7. leetcode算法刷题(二)——动态规划(一)

    上次刷了五六道题,都是关于string处理的,这次想换个知识点刷一下,然后再回头刷string的题,当做复习.. 这几天主要会选择动态规划的题目,因为以前从没刷过这方面的东西,很多东西都不是很懂..就 ...

  8. Leetcode算法刷题:217和219题 Contains Duplicate

    从题目名字就可以看出这两道题是相似的,219是217的加强版 217:Contains Duplicate 题目 给予一个数组,判断是否有重复的元素.如果有就返回True,没有就返回False.以下是 ...

  9. leetcode算法刷题(五)——动态规划(三)

    今天的题目不是leetcode上面的.只是觉得动态规划还是不算很熟练,就接着找了点DP的题练练 最长递增子序列的长度 题目的意思:传入一个数组,要求出它的最长递增子序列的长度.例如:如在序列1,-1, ...

随机推荐

  1. 【转】如何利用logrotate工具自动切分滚动中的日志文件

    FROM : http://www.2cto.com/os/201503/381812.html 在很多实际项目中,应用程序会持续写日志,如果程序代码中没有调用支持自动切分(如按filesize或da ...

  2. Construct Binary Tree from Inorder and Postorder Traversal

    Construct Binary Tree from Inorder and Postorder Traversal Given inorder and postorder traversal of ...

  3. ubuntu15.10 或者 16.04 或者 ElementryOS 下使用 Dotnet Core

    这里我们不讲安装,缺少libicu52自行安装. 安装完成后使用dotnet restore或者build都会失败,一是报编译的dll不适合当前系统,二是编译到ubuntu16.04文件夹下会产生一些 ...

  4. PHP Date ( I need to use)

    本文记录项目中用到的 PHP Date 相关,备忘. 日期格式约定为 xx-xx-xx 格式(字符串),例如 2016-03-09. xx-xx-xx -> 时间戳 $date = " ...

  5. Apache下开启SSI配置使html支持include包含

    写页面的同学通常会遇到这样的烦恼,就是页面上的 html 标签越来越多的时候,寻找指定的部分就会很困难,那么能不能像 javascript 一样写在不同的文件中引入呢?答案是有的,apache 能做到 ...

  6. Android闹钟设置的解决方案

    Android设置闹钟并不像IOS那样这么简单,做过Android设置闹钟的开发者都知道里面的坑有多深.下面记录一下,我解决Android闹钟设置的解决方案. 主要问题 API19开始AlarmMan ...

  7. RHEL每天定时备份Oracle

    步骤: (1)创建脚本文件bak_112.sh,内容如下(自动按当前日期备份数据库): #!/bin/sh export ORACLE_BASE=/u01/app/oracle; ORACLE_HOM ...

  8. Codeforces Round #358(div 2)

    A:统计个数题,要注意ans+=a*b+c*d中,如果a*b>int,那么即使ans是long long也会越界,所以ans+=(long long)a*b+(long long)c*d B:模 ...

  9. Windows系统防火墙用法

    1.按下“Win+X”组合键呼出系统快捷菜单,点击打开“控制面板”: 2.将“查看方式”修改为[大图标],然后点击“Windows 防火墙”: 3.在防火墙窗口左侧点击“高级设置”:(若防火墙未开启, ...

  10. A Regularized Competition Model for Question Diffi culty Estimation in Community Question Answering Services-20160520

    1.Information publication:EMNLP 2014 author:Jing Liu(在前一篇sigir基础上,拓展模型的论文) 2.What 衡量CQA中问题的困难程度,提出从两 ...