二分答案Word文档格式.docx

上传人:b****6 文档编号:21174361 上传时间:2023-01-28 格式:DOCX 页数:23 大小:45.56KB
下载 相关 举报
二分答案Word文档格式.docx_第1页
第1页 / 共23页
二分答案Word文档格式.docx_第2页
第2页 / 共23页
二分答案Word文档格式.docx_第3页
第3页 / 共23页
二分答案Word文档格式.docx_第4页
第4页 / 共23页
二分答案Word文档格式.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

二分答案Word文档格式.docx

《二分答案Word文档格式.docx》由会员分享,可在线阅读,更多相关《二分答案Word文档格式.docx(23页珍藏版)》请在冰豆网上搜索。

二分答案Word文档格式.docx

如果num<

m则表示分组过少,则答案在1到mid的区间内;

如果num=m则在mid+1到tot的区间内寻找更优解。

当左右指针重合时,最优解也就找到了。

参考代码:

1programsai;

2var

3m,n,tot:

longint;

4mid,num,l,r:

5i:

integer;

6p,w,t:

array[0..10000]oflongint;

7functionget(x:

longint):

//分组

8var

9i,num:

10begin

11num:

=0;

12t:

=w;

13fori:

=ndownto1do//从儿子找起,以消除后效性

14ift[i]<

xthent[p[i]]:

=t[p[i]]+t[i]

15elseinc(num);

//如果一个组的能力指数之和达到了中间值就加一组

16exit(num);

17end;

18begin

19assign(input,'

sai.in'

);

20reset(input);

21assign(output,'

sai.out'

22rewrite(output);

23readln(n,m,tot);

24w[1]:

=tot;

25fori:

=2tondo

26begin

27readln(p[i],w[i]);

28tot:

=tot+w[i];

29end;

30l:

=1;

31r:

32whilel<

=rdo

33begin

34mid:

=(l+r)>

>

1;

//mid记录了临时的最优解

35num:

=get(mid);

36ifnum>

=mthenl:

=mid+1elser:

=mid-1;

//与组数进行比较,确定下一个搜索区间

37end;

38writeln(r);

//右指针记录的是最优解

39close(input);

40close(output);

41end.

浅析二分答案

二分答案,顾名思义,大家应该想到了二分查找和二分法对题目的优化,我这里要说的二分答案也是如此。

使用范围:

二分答案必须在满足单调性的情况下才可以使用。

例如下面的一道例题:

一个美丽的夜晚,Bingo和他的MM坐在高高的N骨N堆旁看着天上稀稀拉拉的星星。

Bingo对着MM说:

“我们就像指数函数。

你是底数,我是指数。

不管你是大于一还是大于零小于一,我都可一让我们的幸福指数(不同于上面的指数)到正无穷。

”MM说“你是底数,我是指数,我要顺着你改变”。

Bingo一阵感动,但是,作为一个男人,Bingo怎么能委屈自己的MM呢。

Bingo说:

“不行,我会心疼你的。

”MM说:

“我也会心疼你啊”。

…………

【题目描述】

为了不让Bingo和他的MM谁更心疼,也就是让他们一样心疼对方,给你一个数n,请你找出最小的整数x使得xx的位数大于等于n。

【输入】

一个数,n。

【输出】

一个数x,满足xx的位数大于等于n,x-1x-1的位数小于n。

【样例】

heart.in

11

heart.out

【数据规模】

n<

=1,000,000,000,000,000,000。

【时间,内存限制】

各个测试点1s,64M。

题目解析:

这道题目是典型的二分答案,因为随着mid的增大,mid^mid的位数会随之增大而增大,因此满足单调性,可以使用二分答案来求解;

【代码如下】:

programHeart;

 

varl,r,mid:

qword;

n:

begin

readln(n);

l:

r:

=1shl59;

whilel<

rdo{注意这里,一个奇怪的跳出,这种跳出的优点在于不会为输出l还是r来就接}

mid:

=(l+r)shr1;

iftrunc(mid*ln(mid)/ln(10))+1{换底公式求出它的位数,注意要加1}>

=nthenr:

=midelsel:

=mid+1;

end;

writeln(l);

end.

是不是很短,其实二分并不复杂,其实很EASY。

本题的另外一个难点在于怎么由已知的一个十进制的数来求位数。

其实就是高一数学,用上指数函数的换底公式就可以了。

另外需要注意的一点便是二分边界的维护,这个要根据实际情况而定是要打成r:

=mid-1还是r:

=mid;

许多问题不易直接求解,但如果我们却可以判断某个解是否可行.构造函数ok(x),布尔型,若最终答案为ans,当x<

ans(最终答案)时,ok(x)=false,当x>

=ans时,ok(x)=true(反之亦可),则满足了二分的条件.假设有一个高效的求ok(x)的算法,则可以通过二分x来获得ans。

请看下面的题目:

奇怪的函数(xx.pas/c/cpp)

问题描述

使得x^x达到或超过n位数字的最小正整数x是多少?

输入数据

输入一个正整数n。

输出数据

输出使得x^x达到n位数字的最小正整数x。

输入样例

输出样例

时间限制

各测试点1秒

数据规模

=2000000000

分析:

直接求解不容易.但对于给定的x我们容易知道x^x的位数.且对于递增的x,位数不降.于是可以二分.

下面给出位数的求法:

令Xx=10p,只要求出p即可。

两边取对数:

Xlnx=pln10

所以p=xlnx/ln10,位数即[xlnx/ln10]+1

代码:

constoo=2000000000;

var

l,r,m,n:

int64;

functioncheck:

boolean;

begin

m:

if(m*ln(m)/ln(10))>

=n-1thenexit(true)

elseexit(false);

end;

assign(input,'

xx.in'

reset(input);

readln(n);

close(input);

l:

r:

=oo;

whilel<

rdo

ifcheckthenr:

=m

elsel:

=m+1;

assign(output,'

xx.out'

rewrite(output);

writeln(l);

close(output);

电话网络(phone.pas/c/pp)

[题目描述]

由于地震使得连接汶川县城电话线全部损坏,假如你是负责将电话线接到震中汶川县城的负责人,汶川县城周围分布着N(1≤N≤1,000)根按1..N顺次编号的废弃的电话线杆,任意两根电话线杆间都没有电话线相连。

一共P(1≤P≤10,000)对电话线杆间可以拉电话线,其余的由于地震使得无法被连接。

第i对电话线杆的两个端点分别为Ai,Bi,它们间的距离为Li(1≤Li≤1,000,000)。

数据中保证每对(Ai,Bi)最多只出现1次。

编号为1的电话线杆已经接人了全国的电话网络,整个县城的电话线全都连到了编号为N的电话线杆上。

也就是说,你的任务仅仅是找一条将1号和N号电话线杆连起来的路径,其余的电话线杆并不一定要连人电话网络。

电信公司决定支援灾区免费为汶川县城连结K(0≤K<

N)对由你指定的电话线杆。

对于此外的那些电话线,需要为它们付费,总费用等于其中最长的电话线的长度(每根电话线仅连接一对电话线杆)。

如果需要连接的电话线杆不超过K对,那么总支出为0。

请你计算一下,将电话线引到震中汶川县城最少需要在电话线上花多少钱?

[输入格式]

输入文件的第一行包含三个用空格隔开的整数:

N,P和K。

第二行到第P+1行:

每行分别都为空格隔开的整数:

Ai,Bi和Li。

[输出格式]

输出文件中仅包含一个整数,表示在这项工程上的最小支出。

如果任务不可能完成,则输出-1。

[输入样例]

571

125

314

248

323

529

347

456

[输出样例]

4

这是一道典型的二分答案题,先确定一个长度下限m,大于m的将为免费的。

这样对给出的图中,若某条边小于m,则赋值为0,否则赋值为1。

求1到N的最短路即可。

如果最短路<

=电信公司提供的数目,说明m可行,接下来二分枚举比m小的值,反之二分枚举比m大的值。

const

maxn 

=1000;

maxm 

=10000;

oo 

=100000000;

g,gg 

:

array[1..maxn,1..maxn]oflongint;

array[1..maxm]oflongint;

vis 

array[1..maxn]ofboolean;

array[1..maxn]oflongint;

n,m,k,u,v,l,r,mid,i,j:

longint;

functionok(x:

i,j,l,r,u,v 

fori:

=1tondo

forj:

ifgg[i,j]<

oothen

=xtheng[i,j]:

=0elseg[i,j]:

d[1]:

=2tondop[i]:

=2tondovis[i]:

=false;

vis[1]:

=true;

u:

=d[l];

forv:

ifp[u]+g[u,v]<

p[v]then

p[v]:

=p[u]+g[u,v];

ifnotvis[v]then

inc(r);

d[r]:

=v;

vis[v]:

vis[u]:

inc(l);

ifp[n]<

=kthenexit(true)elseexit(false)

phone.in'

phone.out'

readln(n,m,k);

=1tondoforj:

=1tondogg[i,j]:

=1tomdo

readln(u,v,gg[u,v]);

gg[v,u]:

=gg[u,v];

ifgg[u,v]>

rthenr:

=gg[u,v]

g:

=gg;

mid:

ifok(mid)then

=mid+1

ifok(l)thenwriteln(l)elsewriteln(-1);

close(output)

集训第七次考试第四题二分答案

注:

二分应该时目前我用的最少的一种思想,已经两次遇到了。

什么样的题目能用二分做呢?

常见的有在一堆极大值中找最小值或在一堆极小值中找最大值,数据量大于10000为二分答案的提示,二分可以减小答案范围,变成log级别的。

二分的关键就是当l与r相等的时候是最大值,如果当前解比mid大,就在mid和r中找,反之在l和mid中找。

l和r为限定的最大值和最小值。

例题:

现在根中有n个人,他们的联络网型成一棵以团藏为根的树,有边相连代表两人可以直接联络。

每个人有一个代号,团藏代号为1,且除团藏外每个人的父节点的代号小于他自己的代号。

晓的活动暂时放缓,团藏要当火影的野心一天比一天大,所以他给根的成员分别下达紧急任务,根需要分成m组行动,每个组必须满足如下条件:

每个人有一个能力指数(就是贤、力、精、幻、忍、体的综合指数),一个组的能力指数是全组人能力指数之和。

为了分组较为平均,团藏希望平均度尽可能大。

可怜的佐井迫于团藏的威胁,被要求算出这个最大值,不管怎么说,佐井是个好孩子~而且他只会拿笔画画,不会算这种问题~你就帮帮他好了~~

sai

n,m,和团藏的能力指数(1<

此人的父节点代号和他的能力指数(活动程度值为正整数,不超过30,行数就是他本身的代号)

SAMPLEINPUT(filesai.in)

SAMPLEOUTPUT(filesai.out)

分析:

这个题目描述告诉我们,我们的目标是在保证为m组的情况下,在各组都极大时找一个最小值,而数据量为10000,所以能用二分做。

二分时以每组最小价值为二分依据,设定一个最大价值:

总价值divm+1,一个最小价值1;

二分mid:

=(l+r)shr1;

判断当价值为mid时能达到的组数,如果小于要求组数,就证明价值太大了,令r等于mid反之令l等于mid,一直到l与r相等就找到了最优解。

代码:

var

n,m,l,r,i,mid,zhi:

s,f,sc:

array[1..10000]oflongint;

functioncal(x:

{计算以x为答案时组数}

i,now,ans:

sc:

=s;

ans:

=ndownto1do{依然是倒序}

ifsc[i]>

=xthen{只要当前父节点已经能满足值为x,就算一组}

inc(ans);

{ans为组数}

now:

=f[i];

{递归减去已经抛开的一枝}

whilenow<

0do

sc[now]:

=sc[now]-sc[i];

=f[now];

exit(ans);

readln(n,m,zhi);

s[1]:

=zhi;

{s数组记录当前父节点的所有儿子的价值与其之和}

readln(f[i],zhi);

s[i]:

=ndownto2do{计算所有父节点的总值,倒序消除后效型}

inc(s[f[i]],s[i]);

ifm=1then

writeln(s[1]);

exit;

{特殊情况}

=s[1]divm+1;

{先找一个可能的最大值和最小值,然后逐步

缩小答案范围,这是二分答案的关键}

whiler-l>

1do{一直找到r与l相等就证明已经找到了最优解}

=(l+r)div2;

{二分,效率为log级别}

ifcal(mid)<

mthenr:

=mid;

{cal计算以mid为答案时的组数

如果组数小,就证明值太大,

反之就是值太小,变换l,r}

pku3657:

很有意思的题,大意是给你若干句形如a,b,c的描述,表示a~b的最小值为c,要你求第一句出现矛盾的话。

乍一看没什么好想法,模拟吧,不可能,线段树吧,判不出,怎么办?

回过头想想,为什么麻烦了,麻烦在了哪里,依我看,就是麻烦在了"

求第一句出现矛盾的话"

上,"

第一句"

会卡死了我们的思路,怎么解决呢?

二分答案!

二分的性质很显然,解会是连续的,而且二分答案之后就可以排序了,此为此题收获之一,二分答案以获得更多信息和更宽松的条件

好了,排完序之后容易想到按c从大到小排序,有如下两种情况可能产生矛盾:

如果一段区间的最小值已知为c1了,那么<

c1的值在这段区间上是不可能出现的了,就相当于拿到值为ci的一堆区间时(注意,可能不止一个),对整段区间中没有颜色的点染上ci的颜色(哦,不记得说了,先给区间离散化一下),如果最后发现这一段没染到一个,那么就矛盾了;

题目有要求任意两个仓库的存量不能相同,也就是说,对于值同为ci的区间,如果它们的并不是一个整区间的话,显然会出现矛盾(ci的存量要出现在多个地方)。

此为此题收获之二,细致的读题是ac的必要条件。

第二种情况我自己就没有想到。

这个染色的过程用什么东西来实现?

线段树?

麻烦。

模拟?

不予评价。

这都不是最佳选择。

由于每个点只能被染色一次,那么并查集就能够胜任这个过程了。

具体方法就是每个点的f[i]记录当前它被一整段区间所覆盖的最左边那个点,这样,每次给区间染色就可以用并查集做到均摊O(alpha(n))的了。

并查集的妙用,此为此题收获之三

看这个神奇的数据

103

1101

115

10104

输出3的同学要注意了,普通的离散化不能区分[a,a]U[b,b]和[a,b],那么我们离散化的时候往[a,b](a+1<

b)中插一个点就可以了。

离散化时的细节(好像离散化经常要插点啊什么的),此为此题收获之四

viewplaincopytoclipboardprint?

programsyj;

{erfenans+rangecovering_usingbingchaset}

maxn=25000+5;

varn,q,nn,l,r,mid,i:

x,c,p,f,color:

array[0..maxn*4]oflongint;

a:

array[1..maxn]oflongint;

proceduresort1(l,r:

longint);

vari,j,k,z:

i:

=l;

j:

=r;

k:

=x[(l+r)div2];

repeat

whilex[i]<

kdoinc(i);

whilex[j]>

kdodec(j);

ifi<

=jthenbegin

z:

=x[i];

x[i]:

=x[j];

x[j]:

=z;

=c[i];

c[i]:

=c[j];

c[j]:

inc(i);

dec(j);

untili>

j;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 数学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1