【数论 Day2】基础归纳法 题解

题目: http://www.cnblogs.com/ljc20020730/p/6919989.html

1.烧水问题SDOI2008(山东省队选拔)

对于本题,O(n2)的贪心算法很好找出,就是让前几杯水都加热到100℃后面进行热传递。

打印出前几项,会发现规律……可以优化到O(n)。 或者,也可以无耻地打表……

提醒:令第一杯水需要提高t度,找出第二杯、第三杯……需要提高温度的比例关系,找规律解决。

推倒如下:

设沸腾温度为a

则第一杯温度为a,需要加热t1=a

第二杯可以中和的最高温度为a/2,需要加热t2=a/2

第三杯可以中和的最高温度为t3=(a/4+a)/2=5a/8,需要加热t3=3a/8

第四杯可以中和的最高温度为t4=((a/8+5a/8)/2+a)/2=11a/16,需要加热t4=5/16

则t3/t2=3/4=1-1/4,

t4/t3=5/6=1-1/6

…………………………

继续推导得t(n+1)/t(n)=1-1/2n

根据题目描述及物理常识,我们至多能往当前的杯子里分配(现在花费的总热量/i)的热量,而且一定有办法做到。

所以,实际上第i杯水要花费(上一次花费的热量*(2*i-i)/(2*i))单位热量。

var
  n,i:longint;
  cur,tot:double;
begin
assign(input,‘heat.in‘);
assign(output,‘heat.out‘);
reset(input);
rewrite(output);
  readln(n);
  cur:=420000.00/n;
  tot:=0;
  for i:=1 to n-1 do begin
    tot:=tot+cur;
    cur:=cur*(2*double(i)-1)/(2*double(i))
  end;
  writeln(tot+cur:0:2);
  close(input);
  close(output);
end.

2.六边形(hexagons.pas/c/cpp)

首先讲一种暴力的方法orz

●暴力: 一圈一圈的加,加到i<a or j<b or k<c。

ans:=7; //红色线为公共点。
i:=2;j:=2;k:=2;
while i<a do begin
  ans:=ans+j+k-1;
  i:=i+1;
end;
while j<b do begin
  ans:=ans+i+k-1;
  j:=j+1;
end;
while k<c do begin
  ans:=ans+i+j-1;
  k:=k+1;
end;
writeln(ans);

接下来讲一种O(1)的算法:

直接ans=a*c+a*b+b*c-c-b-a+1

看到下面看到分成3块的面积和为ac+bc+ab

重叠算一次的a+b+c

重叠算两次的1(交点)

所以ans=ac+bc+ab-(a+b+c)+1=a*c+a*b+b*c-c-b-a+1

程序如下:

var a,b,c:longint;
begin
assign(input,‘Hexagons.in‘);
assign(output,‘Hexagons.out‘);
reset(input);
rewrite(output);
 readln(a,b,c);
 writeln(a*c+a*b+b*c-c-b-a+1);
close(input);
close(output);
end.

3.最大子序和

对于样例的解释图:

输入数据,不需要保存序列,可马上序列前缀和为s[i]。q[i]队列维护选取范围的编号,l,r分别表示队列的首尾指针。

队列放起始点

初始化l=0 r=-1

首出队:i-q[l]>B

尾出队:s[q[r]]>=s[i-a]

入队:inc(r);q[r]:=i-a;

ans:=max(s[i]-s[q[l]],ans);

程序如下:

var l,r,a,b,n,i,t,max:longint;
    s,q:array[0..500000]of longint;
begin
assign(input,‘max.in‘);
assign(output,‘max.out‘);
reset(input);
rewrite(output);
 readln(n,a,b);
 s[0]:=0;
 for i:=1 to n do begin
  read(t);
  s[i]:=s[i-1]+t;
 end;//前缀和
 l:=0; r:=-1;
 max:=-maxlongint;
 for i:=a to n do begin
  if (l<=r)and(i-q[l]>b) then inc(l);//当l在r前面并且当前的长度超过B,出队
  while (l<=r)and(s[i-a]-s[q[r]]<=0) do dec(r);//当l在r的前面并且新加入队列的数为负数,那么得出的答案一定会小于某个数
  inc(r); q[r]:=i-a;//扩充队列
  if s[i]-s[q[l]]>max then max:=s[i]-s[q[l]];//s[i]-s[q[l]]表示 i 到 当前队列起始点这么多数的和
 end;
 writeln(max);//输出
 close(input);
 close(output);
end.

这样就可以使平均时间复杂度降为O(n2)以下,关键就是上面的当l在r的前面并且新加入队列的数为负数,那么得出的答案一定会小于某个数,判掉

4.哥德巴赫矩阵

运用筛法求质数的方法,建立一个布尔数组a[]。

=s[x2]-s[x1-1])*(s[y2]-s[y1-1])

观察上面的规律(除2以个的质数的增加)编程实现。

复杂度:预处理O(MAXN*√MAXN),处理s[]为O(N),查询O(1)。

程序如下:

const maxn=1000000;
var u:array[1..10000000]of boolean;
    s:array[0..10000000]of int64;
    i,m,x1,y1,x2,y2:longint;
    now:int64;
Procedure prime(n:longint);
  var i,j:longint;
begin
  for i:=2 to n do
    if not u[i] then begin
      j:=i+i;
      while j<=n do begin
        u[j]:=true;
        inc(j,i);
      end;
    end;
end;
begin
assign(input,‘pmatrix.in‘);
assign(output,‘pmatrix.out‘);
reset(input);
rewrite(output);
  prime(maxn);
  s[1]:=0; s[2]:=0;
  now:=0;
  for i:=3 to maxn do begin
   if u[i]=false then inc(now);
   s[i]:=now;
  end;
  readln(m);
  for i:=1 to m do begin
  readln(x1,y1,x2,y2);
  writeln((s[x2]-s[x1-1])*(s[y2]-s[y1-1])) ;
  end;
  close(input);
  close(output);
end.
时间: 2024-10-13 11:03:51

【数论 Day2】基础归纳法 题解的相关文章

POJ 2608 Soundex 基础题题解

基本的编程能力考查. 注意: 1 下标处理 2 审查题意,并严格根据题意去重. 3 如何把代码写清晰精简. #include <stdio.h> #include <string.h> const short MAX_LETTER = 21; const short ALP_LEN = 26; short Letter[ALP_LEN] = {-1, 1, 2, 3, -1, 1, 2, -1, -1, 2, 2, 4, 5, 5, -1, 1, 2, 6, 2, 3, -1, 1

【数论 Day2】基础归纳法 题目

20170530-1数论_归纳 题解:http://www.cnblogs.com/ljc20020730/p/6920046.html 日期 序号 题目名称 输入文件名 输出文件名 时限 内存 算法 难度 分类 081105 1 烧水问题 heat.in heat.out 1s 256MB 数学 2 03数论_归纳 120912 2 六边形 Hexagons.in hexagons.in 1s 256M 数论 1 03数论_归纳 081106 3 最大子序和 max.in max.out 1s

NOIP2011 Day1,Day2 T1 T2 题解

D1T1:铺地毯(carpet.cpp/c/pas) [题目分析] 分析题目我们可以发现,本题是一个比较简单的枚举,我们可以从后向前扫描,找到的第一个覆盖这个点的地毯,这个地毯的编号就是最后一个覆盖这个点的地毯的编号. [程序源代码] //carpet.cpp by JerryXie #include<cstdio> using namespace std; struct carpet { int a,b,g,k; }; carpet c[10001]; int main() { freope

【数论Day4】 数学 题解

题目:http://www.cnblogs.com/ljc20020730/p/7041033.html 1.离散函数(function.pas/c/cpp) 观察右图,图像必须符合任意两点都在直线的下方.故三条直线中只有相邻两顶点之间的连线的斜率最大.故得出一个规律:最大斜率的直线一定由x坐标相邻的两点确定,即Xi-Xi-1最大的点对. O(n)枚举,通过本题. var n,i,ans1,ans2,maxk:longint; a:array[1..200000]of longint; begi

基础搜索算法题解(N-R)

练习链接:http://acm.njupt.edu.cn/vjudge/contest/view.action?cid=171#overview N题 Shredding Company Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 4398 Accepted: 2520 Description You have just been put in charge of developing a new shredder for

Python Day2 基础 操作文件流

1.列表.元组 操作                                                                    推荐书籍    追风筝的人       白鹿原   琳达看美国 2.字符串操作 3.字典操作 4.集合操作 5.文件操作 6.字符编码和转码 7.内置函数 列表,元祖 列表   name = [2,3,4,3]   name.copy()  浅copy        import copy      name2=cooy.deepndcopy

Python day2 基础 2

数据类型初识 1.数字 2 是一个整数的例子.长整数 不过是大一些的整数.3.23和52.3E-4是浮点数的例子.E标记表示10的幂.在这里,52.3E-4表示52.3 * 10-4.(-5+4j)和(2.3-4.6j)是复数的例子,其中-5,4为实数,j为虚数,数学中表示复数是什么?. int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1,即-2147483648-2147483647 在64位系统上,整数的位数为64位,取值范围为-2**63-2**63

noip2014提高组day2二题题解-rLq

(又是昨天的作业……本题写于昨天) (这破题都做这么久,我是不是吃枣药丸……) (好吧这是一道图论题呢) 本题地址:http://www.luogu.org/problem/show?pid=2296 题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通. 2 .在满足条件1 的情况下使路径最短. 注意:图G 中可能存在重边和自环,题目保证终点没有出边. 请你输出符合

基础搜索算法题解(I-M)

练习链接:http://acm.njupt.edu.cn/vjudge/contest/view.action?cid=171#overview I题 Find The Multiple Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 18823 Accepted: 7618 Special Judge Description Given a positive integer n, write a program to fin