[SHOI2002]N的连续数拆分 题解

一道比较简单的数学题。
题目问我们正整数 \(n\) 可以被多少组连续的正整数拆分。那么这些连续的正整数会组成一个公差为 \(1\) 的等差数列。
设数列的首项为 \(a\),末项为 \(b\),则该等差数列的和为 \(\dfrac{(a+b)(b-a+1)}{2}\)
然后来推一波柿子:

\[\because \dfrac{(a+b)(b-a+1)}{2}=n \]

\[\therefore (a+b)(b-a+1)=2n \]

\[\therefore (a+b)(b-a+1)\bmod 2=0 \]

\[\because \text{两数和、差的奇偶性相同} \]

\[\therefore (a+b)\text{ 和 }(b-a)\text{ 的奇偶性相同} \]

\[\therefore (a+b)\text{ 和 }(b-a+1)\text{ 的奇偶性不同} \]

由此,我们只需要枚举 \((a+b)\),判断其是否为 \(2n\) 的因子。若是,则求出 \((b-a+1)\)。如果 \((a+b)\)\((b-a+1)\) 的奇偶性不同,则方案数增加。
时间复杂度为 \(O(\sqrt{n})\),常数为 \(\sqrt{2}\)
\(11\) 行代码(未压行):

#include <bits/stdc++.h>
using namespace std;
long long n;
int main() {
	scanf("%lld",&n);
	n<<=1; // 之后不需要使用 n 了,只需要用 2n,故直接将 n 乘上 2
	int ans=0,m=sqrt(n);
	for (register int i=1,j;i<=m;i++) ans+=!(n%i)&&(i&1)^(n/i&1); // 位运算。等价于 if (n%i==0&&i%2!=n/i%2) ans++;
	printf("%d",ans);
	return 0;
}
posted @ 2020-04-11 13:47  Aehnuwx  阅读(534)  评论(0编辑  收藏  举报