算法优化入门:把正整数n写成连续的正整数之和

算法优化入门:AOJ1830:把正整数n写成连续的正整数之和

题目描述

问题描述:给定n,n写成连续的正整数之和,求所有的方案

样例输入 15

样例输出

1 5
4 6
7 8

样例解释

15=1+2+…+5
15=4+5+6
15=7+8

O ( n 3 ) O(n^3) O(n3)暴力枚举法

#include <bits/stdc++.h>
using namespace std;
int main() {
  int n;
  cin >> n;
  for (int i = 1; i <= n; i++)
    for (int j = i + 1; j <= n; j++) {
      int s = 0;
      for (int k = i; k <= j; k++)
        s += k;
      if (s == n)
        cout << i << " " << j << endl;
    }
  return 0;
}
/**************************************************************
    Problem: 1830
    User: acm
    Language: C++
    Result: 时间超限
****************************************************************/

O ( n 2 ) O(n^2) O(n2)改进的枚举法:

考虑到 i + . . + j i+..+j i+..+j为等差数列其和 s = ( j − i + 1 ) ∗ ( i + j ) / 2 s=(j-i+1)*(i+j)/2 s=(ji+1)(i+j)/2;

#include <bits/stdc++.h>
using namespace std;
int main() {
  int n;
  cin >> n;
  for (int i = 1; i <= n; i++)
    for (int j = i + 1; j <= n; j++) {
      int s = (j - i + 1) * (i + j) / 2;
      if (s == n)
        cout << i << " " << j << endl;
    }
  return 0;
}
/**************************************************************
    Problem: 1830
    User: acm
    Language: C++
    Result: 时间超限
    Time:21 ms
    Memory:2020 kb
****************************************************************/

O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n))部分和:

构造前缀和 S [ n + 1 ] S[n+1] S[n+1] S [ 0 ] = 0 ; S [ i ] = S [ i − 1 ] + i ( i &gt; = 1 ) S[0]=0;S[i]=S[i-1]+i(i&gt;=1) S[0]=0;S[i]=S[i1]+i(i>=1) i + ( i + 1 ) + . . . + j = S [ j ] − S [ i − 1 ] i+(i+1)+...+j=S[j]-S[i-1] i+(i+1)+...+j=S[j]S[i1];
又因为S数组单调 增加,我们可以对于每一个 S [ k ] S[k] S[k],二分查找 y = S [ k ] + n y=S[k]+n y=S[k]+n所在的位置 j j j,如果在就有 S [ j ] − S [ k ] = n S[j]-S[k]=n S[j]S[k]=n所求答案就是 i = k − 1 , j i=k-1,j i=k1,j

#include <bits/stdc++.h>
using namespace std;
int main() {
  int n;
  cin >> n;
 
  vector<int> S(n + 1, 0);
  for (int i = 1; i <= n; i++)
    S[i] = S[i - 1] + i;
  for (int k = 0; k <= n; k++) {
    int x = S[k] + n;
    int j = lower_bound(S.begin(), S.end(), x) - S.begin(); // O(logN)
    if (S[j] == x && j > k + 1)
      cout << k + 1 << " " << j << endl;
  }
  return 0;
}
/**************************************************************
    Problem: 1830
    User: acm
    Language: C++
    Result: 正确
    Time:0 ms
    Memory:2024 kb
****************************************************************/

O ( n ) O(\sqrt n) O(n )数论、因子分解、解方程:

再次考虑方程 2 n = ( j − i + 1 ) ( j + i ) 2n=(j-i+1)(j+i) 2n=(ji+1)(j+i),只要枚举 2 n 2n 2n的每一个因子 p p p和对应的因子 q = 2 n / p q=2n/p q=2n/p则通过方程组 p = j − i + 1 p=j-i+1 p=ji+1 q = i + j q=i+j q=i+j可以求出 i = ( q − p + 1 ) / 2 , j = ( p + q − 1 ) / 2 i=(q-p+1)/2,j=(p+q-1)/2 i=(qp+1)/2,j=(p+q1)/2

#include <bits/stdc++.h>
using namespace std;
int main() {
  int n;
  cin >> n;
  int m = 2 * n;
  for (int p = sqrt(m); p >= 1; p--) {
    if (m % p != 0)
      continue;
    int q = m / p;
    int i = (q - p + 1) / 2;
    int j = (p + q - 1) / 2;
    if (j > i && j - i + 1 == p && i + j == q)
      cout << i << " " << j << endl;
  }
  return 0;
}
/**************************************************************
    Problem: 1830
    User: acm
    Language: C++
    Result: 正确
    Time:21 ms
    Memory:2020 kb
****************************************************************/

总结:

一个问题可以不停被优化真是非常有趣~~

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值