poj 1186 方程的解数

该博客详细介绍了如何解决POJ 1186问题,主要探讨了如何利用哈希技术来计算一个数学方程的解的数量。通过实例输入和输出展示了解题思路和解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方程的解数
Time Limit: 15000MS Memory Limit: 128000K
Total Submissions: 6393 Accepted: 2198
Case Time Limit: 5000MS

Description

已知一个n元高次方程: 
 
其中:x1, x2,...,xn是未知数,k1,k2,...,kn是系数,p1,p2,...pn是指数。且方程中的所有数均为整数。 
假设未知数1 <= xi <= M, i=1,,,n,求这个方程的整数解的个数。 
1 <= n <= 6;1 <= M <= 150。 
 
方程的整数解的个数小于2 31。 
★本题中,指数Pi(i=1,2,...,n)均为正整数。 

Input

第1行包含一个整数n。第2行包含一个整数M。第3行到第n+2行,每行包含两个整数,分别表示ki和pi。两个整数之间用一个空格隔开。第3行的数据对应i=1,第n+2行的数据对应i=n。

Output

仅一行,包含一个整数,表示方程的整数解的个数。

Sample Input

3
150
1  2
-1  2
1  2

Sample Output

178

Source

初学hash做的第一道题,基本是照搬别人的程序。。。。。。看了一遍,自己敲了一遍,发现这是最普通的那种开放寻址加线性探查,然后期间用官方的pow函数死活不过,于是最后妥协了自己写的。。。。。
就是把算式剖开两半,然后对前面三个的结果做hash,之后对后面三个的结果的取反找hash,然后如果加起来是0那就是解。。感觉这个方法比较好,所以也记录一下。
#include <iostream>
#include<algorithm>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define MAX 4444444

using namespace std;
void left_ser(int d, int s);
void right_ser(int d, int s);
void insert_hash(int s);
int Hash(int s);
int getpow(int x, int p);

struct HASH{
    int val;
    int c;
}hash_t[MAX];
int use[MAX] = {0};
int mid, n, m, ans;
int k[11], p[11];

int main()
{
    int i;
    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//    for (i = 0;i < MAX;i ++)
//        hash_t[i].c = 0;
    scanf("%d", &n);
    scanf("%d", &m);
    for (i = 0;i < n;i ++){
        scanf("%d%d", &k[i], &p[i]);
    }
    ans = 0;
    mid = n >> 1;
    left_ser(0, 0);
    right_ser(mid, 0);

    printf("%d\n", ans);
    return 0;
}

void left_ser(int d, int s){
    int i;
    if (d == mid){
        insert_hash(s);
        return;
    }
    for (i = 1;i <= m;i ++){
        left_ser(d+1, s + k[d]*getpow(i, p[d]));
    }
}

void right_ser(int d, int s){
    int pos, i;
    if (d == n){
        s = -s;
        pos = Hash(s);
        if (hash_t[pos].val == s){
            ans += hash_t[pos].c;
        }
        return;
    }
    for (i = 1;i <= m;i ++){
        right_ser(d + 1, s + k[d]*getpow(i, p[d]));
    }
}

void insert_hash(int s){
    int pos = Hash(s);
    hash_t[pos].val = s;
    hash_t[pos].c++;
    use[pos] = 1;
}

int Hash(int s){
    int temp = s;
    while (temp >= MAX) temp -= MAX;
    while (temp < 0) temp += MAX;
    while(use[temp] && hash_t[temp].val != s){
        temp ++;
        if (temp >= MAX){
            temp -= MAX;
        }
    }
    return temp;
}

int getpow(int x, int p) {
    int tmp = 1;
    while (p) {
        if (p&1)
            tmp *= x;
        x *= x;
        p >>= 1;
    }
    return tmp;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值