1. 程式人生 > >高斯求和等差數列前綴和(洛谷1147 連續自然數和)

高斯求和等差數列前綴和(洛谷1147 連續自然數和)

數學 i++ -a 一半 自己 簡潔 空格 ron div

對一個給定的自然數M,求出所有的連續的自然數段,這些連續的自然數段中的全部數之和為M。

例子:1998+1999+2000+2001+2002 = 10000,所以從1998到2002的一個自然數段為M=10000的一個解。

輸入格式:

包含一個整數的單獨一行給出M的值(10 <= M <= 2,000,000)。

輸出格式:

每行兩個自然數,給出一個滿足條件的連續自然數段中的第一個數和最後一個數,兩數之間用一個空格隔開,所有輸出行的第一個按從小到大的升序排列,對於給定的輸入數據,保證至少有一個解。

輸入樣例#1:
combo.in
10000
輸出樣例#1:
combo.out
18 142 
297 328 
388 412 
1998 2002
這是我用前綴和計算的代碼:
#include<bits/stdc++.h>
#define LL long long
using namespace std;

LL s[2000000];

int main()
{
   LL n;
   cin>>n;
   for(LL i=1;i<=2000000;i++)
     s[i]=s[i-1]+i;
   for(LL i=1;i<=2000000;i++)
   {
      if(i<n)
      {
	     for(LL j=i+2;j<=2000000;j++)
	       if(s[j]-s[i]==n)
	         cout<<i+1<<" "<<j<<endl;
	        else
	          if(s[j]-s[i]>n)
	            break;
	  }
	  else break;
   }
   return 0;
}

以下為洛谷一位大神的思路:

整個題就是反向的一個等差數列求和

給出M,有等差數列求和公式得:設區間[x,y]上M=(x+y)*(x-y+1)/2 順便提一下 x-y+1 為自然數個數

化簡得到 y方-y=x方+x-2*M;進一步兩邊同時加一個1/4 可得 (y-1/2)方=(x+1/2)方-2*M;

於是兩邊開方 有y=根號下((x+1/2)方-2*M)+1/2;

那麽我們就枚舉x i=1;i<=M/2;i++ 因為至少是兩個數相加所以枚舉到一半即可;

可以算出每一個x對應的y 只需判斷其是否為整數 如果是那麽合題輸出一組;

由於原大神的代碼和講解不符合,所以我就放上我自己的代碼了(orz馮豫川)

#include<bits/stdc++.h>
using namespace std;
int main()
{
   LL n;
   cin>>n;
   for(int i=1;i<n;i++)
   {
      double h=sqrt((i+0.5)*(i+0.5)-2*n)+0.5;
      if(int(h)==h)
        cout<<int(h)<<" "<<i<<endl;
   }
   return 0;
}

數學方法代碼簡潔了很多不知道大家有沒有發現。

高斯求和等差數列前綴和(洛谷1147 連續自然數和)