2019.7.8 校内测试题 连续数和
题目
连续数和 (num.cpp,1s,128MB)
【问题描述】:
一个正整数有可能可以被表示为 n(10^9>=n>=2)个连续正整数之和,如:
15=1+2+3+4+5
15=4+5+6
15=7+8
根据输入的任何一个正整数,找出符合这种要求的所有连续正整数序列。
【输入文件】:
一个正整数。
【输出文件】:
输出符合题目描述的全部正整数序列,每行一个序列,每个序列都从该序列
的最小正整数开始、以从小到大的顺序打印。如果结 果有多个序列,按各序列
的最小正整数的大小从小到大打印各序列。此外,序列不允许重复,序列内的整
数用一个空格分隔。如果没有符合要求的序列,输出 "NONE"。
【输入输出样例】:
num.in
15
num.out
1 2 3 4 5 4 5 6 7 8
num.in
16
num.out
NONE
【数据规模】:
6 种状态为:(000)(001)(011)(100)(110)(111)
考试得分: 100
主要算法 : 数列(等差数列)
题干:
求一个连续数和为N的数,
应试策略:
运用数学等差数列的基本方法
思考:利用数列最长的长度n:(1+n)*n/2=连续数和,那么可以枚举数列长度
1.枚举数列长度n,根据(a1+a1+n)*n/2=连续数和,求出a1
2.将数列存储到一个结构体中,结构体成员有数列的第一个数a1,数列字符串
3.由于需要字典序最小,又因为每一个数列的a1不同,那么就可以比较a1来进行排序
代码
#include<math.h> #include<stdio.h> #include<stdlib.h> #include<iostream> #include<algorithm> #define LL long long #define FORa(i,s,e) for(LL i=s;i<=e;i++) #define FORs(i,s,e) for(LL i=s;i>=e;i--) #define gc pa==pb&&(pb=(pa=buf)+fread(buf,1,10000,stdin),pa==pb)?EOF:*pa++ #define File(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout) using namespace std; static char buf[10000],*pa=buf,*pb=buf; inline LL read(); LL n,cnt,ct; struct Node{ string s; int a1; }s[50000]; string Turn_s(int x) { string fs; fs.clear(); while(x) { fs=char((x%10)+'0')+fs; x/=10; } return fs; } bool cmp(Node a,Node b) { return a.a1<b.a1; } int main() { File("num"); n=read(); cnt=-1+ceil(sqrt(4+8*n)/2); FORa(i,2,cnt) { if((2*n+i-i*i)%(2*i)==0) { LL a1=(2*n+i-i*i)/(2*i); s[++ct].s=Turn_s(a1),s[ct].a1=a1; FORa(j,2,i) s[ct].s=s[ct].s+" "+Turn_s(a1+j-1); } } sort(s+1,s+1+ct,cmp); if(ct==0) printf("NONE"); else FORa(i,1,ct) cout<<s[i].s<<endl; return 0; } inline LL read() { register LL x(0);register LL f(1);register char c(gc); while(c<'0'||c>'9') f=c=='-'?-1:1,c=gc; while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=gc; return x*f; }
非完美算法:
照搬应试策略
正解:
模拟方法:
照搬应试方法
因数分解方法:
1.设L,R,则S=(L+R)*(R-L+1)/2
2.那么 2S=(L+R)*(R-L+1)
3.将2S分解为两个因数的乘积形式,求出L,R
总结:
1.数列的基本运算
2.因数分解思想