题意
序列1,2,...n,求出所有子串,使得和为m
类型
数学
思路
由求和公式易得
b(b+1)/2 - a(a+1)/2 = m ( 0 <= a < b <= n )
配方得
(b+1/2)^2 - (a-1/2)^2 = m
然后
(b-a)(a+b+1) = 2m
这样出现了两个数相乘得2m
这些数必然是2m的质因子相乘
状态枚举,然后去重去不合法,然后排序,就OK
(其实,a+b+1 < sqrt(2m) 所以枚举就可以了)
收获
一种解二元二次不定方程的思路(配方,平方差公式,质因子枚举)
代码
/************************************************************************* > File Name: hd2058.cpp > Author: Shine > Created Time: 2013-06-27 下午 6:16:55 > QuestionType: 数学 > Way: (b-a)(a+b+1) == 2m (其实暴力枚举a+b+1的值就可以了(到根号2m)) > Submit: 3WA 1AC > Gain: 尝试了一下状态枚举和分解质因子的写法 > Experience: 对于每一步,想想,有必要吗?暴力可以吗? ************************************************************************/ #include <cstdio> #include <algorithm> using namespace std; #define N 100050 int prime[N]; int p = 0; int getprime() { int i, j; for (i = 2; i < N; i++) { for (j = 2; j * j < i; j++) { if (i % j == 0) break; } if (j * j >= i) prime[p++] = i; } return p; } int primInM[100]; struct RE { int a, b; bool operator < (const RE &c) const { if (a != c.a) return a < c.a; else return b < c.b; } }re[10000]; int main() { getprime(); int n, m; while (~scanf("%d%d", &n, &m) && n && m) { int dm = 2*m; int i; int mp = 0; //分解质因子 for (i = 0; i < p && dm > 1; i++) { while (dm % prime[i] == 0) { dm /= prime[i]; primInM[mp++] = prime[i]; } } if (dm > 1) primInM[mp++] = dm; dm = 2*m; int rep = 0; int endstate = 1<<mp; int state = 0; while(state < endstate) { int A = 1, B = 1; for (i = 0; i < mp; i++) { if (state & (1<<i)) A *= primInM[i]; } B = dm / A; int a = (B-A-1)/2; int b = (A+B-1)/2; if (!(a < 0 || b <= 0 || a >= b) && (b-a)*(a+b+1) == dm && b <= n && a <= n) { re[rep].a = a; re[rep].b = b; rep++; } state++; } sort(re, re+rep); int prea = -1, preb = -1; for (i = 0; i < rep; i++) { if (re[i].a == prea && re[i].b == preb) continue; prea = re[i].a; preb = re[i].b; printf("[%d,%d] ", re[i].a+1, re[i].b); }puts(""); } return 0; }