算法优化入门: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=(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 ( 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
>
=
1
)
S[0]=0;S[i]=S[i-1]+i(i>=1)
S[0]=0;S[i]=S[i−1]+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[i−1];
又因为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=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) O(n)数论、因子分解、解方程:
再次考虑方程 2 n = ( j − i + 1 ) ( j + i ) 2n=(j-i+1)(j+i) 2n=(j−i+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=j−i+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=(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
****************************************************************/
总结:
一个问题可以不停被优化真是非常有趣~~