求出全体的连天的自然数段,这一个再而三的本来数段中的全体数之和为M

对一个加以的当然数M,求出全部的一连的自然数段,这个接二连三的本来数段中的全体数之和为M。

P114七 再三再四自然数和

主题素材叙述

对四个加以的当然数M,求出全体的连日的自然数段,那几个延续的本来数段中的全体数之和为M。

事例:一⑨玖7+1玖9九+2000+2001+二零零零 =
一千0,所以从一九九九到2003的二个自然数段为M=10000的多个解。

事例:一九9八+19九陆+三千+200一+二〇〇二 =
一千0,所以从一99陆到二〇〇二的三个本来数段为M=一千0的二个解。

难点叙述

对三个加以的本来数M,求出全体的接连的当然数段,这一个一连的当然数段中的全体数之和为M。

事例:一九九七+19玖捌+两千+200一+二〇〇四 =
一千0,所以从一9玖七到2001的三个自然数段为M=一千0的3个解。

输入输出格式

输入格式:

蕴涵三个整数的独立一行给出M的值(10 <= M <= 2,000,000)。

出口格式:

每行多个自然数,给出二个满意条件的总是自然数段中的第三个数和最后三个数,两数以内用2个空格隔离,全数输骑行的率先个按从小到大的升序排列,对于给定的输入数据,保证最少有二个解。

输入格式:

输入输出格式

输入格式:

涵盖二个整数的独立一行给出M的值(拾 <= M <= 贰,000,000)。

出口格式:

每行八个自然数,给出一个满足条件的连日自然数段中的第叁个数和终极2个数,两数里面用一个空格隔开分离,全数输骑行的第2个按从小到大的升序排列,对于给定的输入数据,保障最少有1个解。

输入输出样例

输入样例#1:

combo.in10000

输出样例#1:

combo.out18 142 297 328 388 412 1998 2002

实在那道题数学二分什么的都统统没须要

做一个前缀和

下一场暴力枚举就足以

注意要加剪纸否则超时

世代难忘:

武力出神迹!!!!

 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int MAXN=10000001; 7 int a[MAXN]; 8 int ans=0; 9 int main()10 {11     int n;12     scanf("%d",&n);13     for(int i=1;i<=n;i++)14         a[i]=a[i-1]+i;15     for(int i=1;i<n;i++)16     {17         for(int j=i;j<n;j++)18         {19             if(a[j]-a[i]==n)20             {21                 printf("%d %d\n",i+1,j);22             }23             if(a[j]-a[i]>n)break;24         }25     }26     return 0;27 }

富含二个平头的单身1行给出M的值(十 <= M <= 二,000,000)。

输入输出样例

输入样例#1:

combo.in
10000

出口样例#1:

combo.out
18 142 
297 328 
388 412 
1998 2002

小水题,等差数列公式推壹推就好了,注意浮点数模型误差。

 1 #include <bits/stdc++.h>
 2 const int INF = 0x3f3f3f3f;
 3 inline int min(int a,int b){return a > b? b : a;}
 4 inline int max(int a,int b){return a < b? b : a;}
 5 inline int read(long long &x){
 6     x = 0;char ch = getchar();char c = ch;
 7     while(ch > '9' || ch < '0')c = ch, ch = getchar();
 8     while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0',ch = getchar();
 9     if(c == '-') x = -x;
10 }
11 long long m;
12 int main(){
13     read(m);
14     for(long long x = 1;x < m;x ++)
15     {
16         long long k = x * x - x + 2 * m;
17         long long y = (long long)(sqrt(1/4.0 - x + x * x + 2 * m) - 1/2.0);
18         if(y < x)continue;//防止取重 
19         //防止误差,分别考察y,y-1,y+1 
20         if(y * y + y == k)printf("%lld %lld\n", x, y);
21         y ++;
22         if(y * y + y == k)printf("%lld %lld\n", x, y);
23         y -= 2;
24         if(y * y + y == k)printf("%lld %lld\n", x, y);
25     }
26     return 0;
27 }

 

出口格式:

每行八个自然数,给出三个满意条件的连日自然数段中的第多个数和终极一个数,两数里面用叁个空格隔绝,全部输骑行的第3个按从小到大的升序排列,对于给定的输入数据,保障最少有二个解。

输入样例#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;
}

 以下为洛谷1人大神的思路:

任何题就是反向的一个等差数列求和

给出M,有等差数列求和公式得:设间隔[x,y]上M=(x+y)*(x-y+一)/二附带提一下 x-y+壹 为本来数个数

化简获得 y方-y=x方+x-二*M;进一步两边同时加三个四分之一 可得
(y-二分之一)方=(x+二分一)方-二*M;

于是乎两边开方 有y=根号下((x+百分之五10)方-二*M)+1/2;

那么咱们就枚举x i=1;i<=M/二;i++
因为至少是多个数相加所以枚举到50%就能够;

能够算出每三个x相应的y 只需判别其是不是为整数 如果是那么合题输出1组;

鉴于原大神的代码和教授不切合,所以本人就放上作者要好的代码了(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;
}

 

数学方法代码简洁了很多不知道大家有没有发现。

相关文章