解题报告 报数

 

1.        题目

报数(Number. pas/c/cpp

题目描述

     A营和B营之间不合已经是整个部队公开的了,所以他们没事就找对方麻烦。因为部队做集体训练,A营和B营很不幸分在了一组。。。所以又不安静了。。。

     A营和B营都要报数,但是他们报数都很有意思,假设A营报的数为一个非递减的整数序列S1S2S3,……,Sn+1Si<=Si+1)。而B营报的数为序列M1M2,…,MS的“M序列”,其中Mi=(Si+Si+1)/2

    例如,S=(1, 3, 3, 5),则M=(2, 3, 4)

    警官要求先报出M序列,B营当然不会放过这么好一个为难A营的机会,所以他们会一顿乱报,当然还是满足Si<=Si+1的。而你的任务就是帮助A营求出他们报数的S序列有多少种情况。  

输入数据

   第一行一个数n表示M的个数

    第二到N+1行每行一个数Mi

输出数据

   一个整数,表示A营有多少种报数方案

样例输入

3

2

5

9

 

样例输出

4

(存在如下四个报数方案满足要求:

2,2,8,10;

1,3,7,11;

0,4,6,12;

-1,5,5,13。)

 

数据范围

50%的数据n<=1000,mi<=20000

    100%的数据2<=n<=100000,mi<=109.

 

2.        题目实质

数学数列部分习题的代码实现。

3.        算法

数论,不,这就是一个数学题。

首先,观察这个生成的数列,可以发现首项一确定,整个数列就可以确定了,所以我们只需要求出首项的范围。

S序列的第一项为k,那么后面几项就可以写成关于k的多项式:

S1=k

S2=2*m1-k

S3=2*m2-2*m1+k

……

然后根据S序列的非递减性质,有S1<=S2<=S3<=.

所以有

    k<=2*m1-k

    2*m1-k<=2*m2-2*m1+k

    ……

可以得到n个关于k的不等式,而且都是有规律的,可以在O(n)的时间内解出:

      x[i]+2*h[i-2]-2*h[i-1] I 为偶)<= s[I] <= x[i]+2*h[i-2]-2*h[i-1] I 为奇)

由于k的值和S序列是一一对应的,所以k的取值的个数(b-a)就是满足要求的S序列的个数。

4.        注意事项

这个题代码很短,推导过程很长……

5.        程序代码

FHAI   Pascal

var

h,x:array[-3..100004]of longint;

r,l,n,i,j,t:longint;

begin

assign(input,'number.in');reset(input);

assign(output,'number.out');rewrite(output);

readln(n);

for i:=1 to n do

      begin

      readln(x[i]);

      x[i]:=x[i]*2;

      inc(h[i],x[i]);

      inc(h[i],h[i-2]);  //这样,每个 h 表示的是在他之前,奇偶性与他相同的各项的和。

      end;

 

r:=maxlongint;l:=-maxlongint;

for i:=1 to n do

      begin

      t:=x[i]+2*h[i-2]-2*h[i-1];

      if i mod 2=0 then

           begin

             if l<((-t) div 2)then l:=(-t) div 2;  //表示各个偶数项和的 h 少加一个,所以 t<0 ,或者为了怕出错,可以直接取 abs(t)

           end

      else if r>(t div 2 )then r:=t div 2;

      end;  //求出 l r 即求出了首项的范围。

if r<l then write(0)

    else write(r-l+1);   //首项确定,整个数列即可确定。

close(input);close(output);

end.

原文地址:https://www.cnblogs.com/SueMiller/p/2130957.html