【LightOJ - 1278】 Sum of Consecutive Integers 【简单公式变形-算数基本定理】

Given an integer N, you have to find the number of ways you can express N as sum of consecutive integers. You have to use at least two integers.

For example, N = 15 has three solutions, (1+2+3+4+5), (4+5+6), (7+8).

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a line containing an integer N (1 ≤ N ≤ 1014).

Output
For each case, print the case number and the number of ways to express N as sum of consecutive integers.

Sample Input
5
10
15
12
36
828495
Sample Output
Case 1: 1
Case 2: 3
Case 3: 1
Case 4: 2
Case 5: 47

分析: 首先要求 连续序列和为n的方案数,一看到连续序列和,等差数列求和公式一定没跑。假设连续区间为[L,R] ,则根据题意:
(L+R)*(R-L+1) =2*N
令 a = (L+R)
令 b=(R-L+1)
a*b=2*N (a 和 b 我们可以枚举 2*N的因子得到 )
我们可以解出
L=(a-b+1) /2
R=(a+b-1)/2
然后因为a和b我们可以通过枚举因子得到,然后问题就解决了,但是看了下时间复杂度,枚举因子sqrt(2*n) *T 肯定超时。
只能再化简一下了,我们要求的L和R 一定要是整数,a和b什么情况下才可以满足呢?我们发现a和b一个是偶数一个是奇数一定可以满足这个条件。
但是怎么知道 2*N可以分解为多少个 奇数*偶数呢? 这里我们可以通过 算数基本定理来考虑,假设N*2=p1^ r1 p2^r2 p3 ^r3….pk^rk (分解整数的时间复杂度为o ( n ^ ( 1 / 4 ) ) )
要想分解为偶数*奇数,那么我们可以发现,偶数一定是由质因子2来提供的,我们把2^r 看做一个整体,从后面的部分中挑出一个因子 来和2^r组成一个数,剩下的部分为一个数字,那么前一个数一定为偶数,后一个数一定为奇数。(这里的通过质因子分解 ,来划分为两个数字,是一种组合在里面,如果不理解的话,可以找找规律)

代码

 #include<bits/stdc++.h>
using namespace std;
#define LL long long

const int N = (int)1e7+11;
const int M = 1e6+11;
const int mod = 1e9+7;
const int inf =0x3f3f3f3f;

bool su[N+1]={1,1,0};int prm[664579+11],sz; // prm如果也开1e7的话 会MLE
void init(){
    for(LL i=2;i<N;i++){
        if(!su[i]){
            prm[sz++]=i;
            for(LL j=i*i;j<N;j+=i){
                su[j]=1;
            }
        }
    }

   // cout<<sz<<endl;
}

int main(){
    init();
    int cas=1;
    int T ;scanf("%d",&T);
    while(T--){
        LL n;scanf("%lld",&n);
        LL m=n;
        LL a=0,b=1; n*=2;
        for(LL i=0;prm[i]*1ll*prm[i]<=n&&i<sz;i++){
            if(n%prm[i]==0){
                int cnt=0;
                while(n%prm[i]==0){
                    cnt++;
                    n/=prm[i];
                }
                if(i==0) {
                     a=cnt;
                     continue;
                }
                b*=(cnt+1);
            }
        }
        if(n!=1) b*=2;

        LL ans;
        if(a==0 || 1==b) ans=1;   
        else ans=b;
        printf("Case %d: %lld\n",cas++,ans-1);// 因为多算了 一个 (2*N ,1) 这个组合,所以要减去
    }

return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值