題目鏈接:jzoj 2752
題目
把一個正整數分成一列連續的正整數之和。這個數列必須包含至少兩個正整數。你需要求出這個數列的最小長度。如果這個數列不存在則輸出。
輸入
每行包含一個正整數。
每個文件包含多行,讀入直到文件結束。
輸出
對於每個,輸出一行,爲這個數列的最小長度。
輸入樣例
9
2
輸出樣例
2
-1
數據範圍
對於所有數據,。
思路
一道思維題。
首先,我們可以知道,當爲或的時候,答案是。
然後,我們可以通過觀察數據與打表發現,當爲奇數的時候(除了),答案都爲。
接着,我們再來處理爲偶數的情況,可以分兩種情況討論:
- 數列的長度爲偶數,則數列的平均值是一個小數(的樣子)。而我們要讓這個數列的數儘可能少,這個數列的和有不變,就只能讓數列的平均值儘可能的大。我們可以找出最大的奇數因子,而長度就爲:。
- 數列的長度爲奇數,那麼數列的平均值就是一個整數,我們只要直接枚舉長度,找到最小的奇數長度就可以了。
然後那個小答案就是那個,若是兩個都沒有答案就輸出。
代碼
#include<cstdio>
#define rr register
#define ll long long
using namespace std;
ll n;
int main() {
while (scanf("%lld", &n) == 1) {//讀入
if (n < 3) {//n爲1或者2的話都是-1
printf("-1\n");
continue;
}
if (n % 2 == 1) {//其它的如果是奇數答案都爲2
printf("2\n");
continue;
}
ll nn = n, ans = 100000000000000;
while (nn % 2 == 0) nn >>= 1;//求出這個數的最大奇數因子
if ((nn + 1) / 2 - n / nn >= 0) {//求出偶數長度中最小的長度
ans = n / nn * 2;
if ((nn + 1) / 2 - n / nn == 0)
ans--;
}
for (rr ll int i = 3; i <= ans && i * i <= n && i <= nn; i += 2)//找出有沒有奇數長度更小的
if (n % i == 0) {
ans = i;
break;
}
if (ans == 100000000000000) printf("-1\n");//沒有找到序列
else printf("%lld\n", ans);//輸出
}
return 0;
}