zoukankan      html  css  js  c++  java
  • 【数学】【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~ imes~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~=~egin{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
    ", s, s);
    	else {
    		qw(ans, ' ', true);
    		qw(ans + ss - 1, '
    ', true);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [CQOI2011]放棋子
    [CF1192B]动态直径
    [CERC2016]凸轮廓线
    19_08_14-19_08_21校内训练 补题
    [模板]线性递推+BM
    19_08_10[校内训练]割图
    [模板]多项式封装(无讲解)
    19_07_11校内训练[字串染色]
    CF990G
    19_07_09校内训练[分组]
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10091358.html
Copyright © 2011-2022 走看看