1. 程式人生 > >【數學】【P5077】 Tweetuzki 愛等差數列

【數學】【P5077】 Tweetuzki 愛等差數列

Description

Tweetuzki 特別喜歡等差數列。尤其是公差為 \(1\) 且全為正整數的等差數列。

顯然,對於每一個數 \(s\),都能找到一個對應的公差為 \(1\) 且全為正整數的等差數列各項之和為 \(s\)。這時,Tweetuzki 想知道,滿足這樣條件的等差數列,最小的首項是多少。

由於 Tweetuzki 的數學非常差,尤其是因式分解,所以請你告訴他結果。

Input

輸入僅包含一行一個整數 \(s\)

Output

輸出一行兩個用空格隔開的整數代表首項和末項

Hint

對於 \(10\%\) 的資料,\(1~\leq~s~\leq~10^6\)
對於 \(100\%\)

的資料,\(1~\leq~s~\leq~10^{12}\)

Solution

考慮前 \(10\%\) 的點,暴力列舉首項,列舉完首項就可以 \(O(1)\) 判斷是否合法了。期望得分 10 pts

考慮剩下的部分:

一個等差數列的長度只有為奇數和偶數兩種可能,下面對這兩種可能分類討論:

對於長度為奇數的情況,設這個等差數列共有 \(2x~+~1\) 項,其中中項(最中間)為 \(a_k\)

因為 \(a_{k-i}~+~a_{k+i}~=~2~\times~a_k\),所以 \(\sum~a_i~=~(2x~+~1)~a_k~=~s\)

同理,對於長度為偶數的情況,設共有 \(2x\)

項,其中中間兩項為 \(a_k~,~a_{k+1}\),因為公差為\(1\),所以即為 \(a_k~,~a_k~+~1\)

於是 \(\sum~a_i~=~x(a_k+a_k~+~1)~=~x~(2a_k~+~1)~=~s\)

由此我們得到了兩種情況的關係式

\[s~=~\begin{cases}(2x~+~1)~a_k \\x~(2a_k~+~1) \end{cases}\]

其中第一種情況長度為奇數,第二種情況長度為偶數。

注意到這兩個式子都是 \(s\) 的因數分解,於是考慮直接列舉 \(x\) 的因數。

在第一種情況下,因為 \(a_k\) 是它的因數,我們考慮列舉 \(a_k\)

,只要列舉到第一個合法的 \(a_k\) 即可停止,

第二種情況下,因為 \(x\) 是它的因數,我們考慮列舉 \(x\),計算所有合法的 \(a_k\)

另外記得特判一個數是由自己做等差數列的情況

Code

#include <cmath>
#include <cstdio>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#define putchar(o) \
puts("I am a cheater!")
#endif
#define rg register
#define ci const int
#define cl const long long

typedef long long int ll;

namespace IPT {
    const int L = 1000000;
    char buf[L], *front=buf, *end=buf;
    char GetChar() {
        if (front == end) {
            end = buf + fread(front = buf, 1, L, stdin);
            if (front == end) return -1;
        }
        return *(front++);
    }
}

template <typename T>
inline void qr(T &x) {
    rg char ch = IPT::GetChar(), lst = ' ';
    while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
    while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
    if (lst == '-') x = -x;
}

template <typename T>
inline void ReadDb(T &x) {
    rg char ch = IPT::GetChar(), lst = ' ';
    while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
    while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
    if (ch == '.') {
        ch = IPT::GetChar();
        double base = 1;
        while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
    }
    if (lst == '-') x = -x;
}

namespace OPT {
    char buf[120];
}

template <typename T>
inline void qw(T x, const char aft, const bool pt) {
    if (x < 0) {x = -x, putchar('-');}
    rg int top=0;
    do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
    while (top) putchar(OPT::buf[top--]);
    if (pt) putchar(aft);
}

ll s, ans = 1000000000000ll, ss;

int main() {
    freopen("1.in", "r", stdin);
    qr(s);
    for (rg ll i = 2; (i * i) <= s; ++i) if(!(s % i)) {     //列舉中項 
        ll k = s / i;
        if (k & 1) {
            ll x = k >> 1;
            if ((i - x) > 0) {
                ans = i - x;
                ss = k;
                break;
            }
        }
    }
    for (rg ll i = 1;  (i * i) <= s; ++i) if (!(s % i)) {   //列舉x 
        ll k = s / i;
        if (k & 1) {
            ll a = k >> 1;
            if ((a - i) > 0) {
                if (ans > a - i) ans = a - i + 1, ss = i << 1;
            }
        }
    }
    if (ans == 1000000000000ll) printf("%lld %lld\n", s, s);
    else {
        qw(ans, ' ', true);
        qw(ans + ss - 1, '\n', true);
    }
    return 0;
}