您的位置:首页 > 其它

hdu 2058:The sum problem

2013-06-27 20:19 295 查看

题意

序列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
;
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]\n", re[i].a+1, re[i].b);
}puts("");
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: