算法優化入門:把正整數n寫成連續的正整數之和

算法優化入門:AOJ1830:把正整數n寫成連續的正整數之和

題目描述

問題描述:給定n,n寫成連續的正整數之和,求所有的方案

樣例輸入 15

樣例輸出

1 5
4 6
7 8

樣例解釋

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

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

#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(n2)O(n^2)改進的枚舉法:

考慮到i+..+ji+..+j爲等差數列其和s=(ji+1)(i+j)/2s=(j-i+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(nlog(n))O(n\log(n))部分和:

構造前綴和S[n+1]S[n+1]S[0]=0;S[i]=S[i1]+i(i&gt;=1)S[0]=0;S[i]=S[i-1]+i(i&gt;=1)i+(i+1)+...+j=S[j]S[i1]i+(i+1)+...+j=S[j]-S[i-1];
又因爲S數組單調 增加,我們可以對於每一個S[k]S[k],二分查找y=S[k]+ny=S[k]+n所在的位置jj,如果在就有S[j]S[k]=nS[j]-S[k]=n所求答案就是i=k1,ji=k-1,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)數論、因子分解、解方程:

再次考慮方程2n=(ji+1)(j+i)2n=(j-i+1)(j+i),只要枚舉2n2n的每一個因子pp和對應的因子q=2n/pq=2n/p則通過方程組p=ji+1p=j-i+1q=i+jq=i+j可以求出i=(qp+1)/2,j=(p+q1)/2i=(q-p+1)/2,j=(p+q-1)/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
****************************************************************/

總結:

一個問題可以不停被優化真是非常有趣~~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章