hdu 2058:The sum problem

题意

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

 

 

posted on 2013-06-27 20:19  ShineCheng  阅读(264)  评论(0编辑  收藏  举报

导航