NOI2001 方程的解数

1735 方程的解数

http://codevs.cn/problem/1735/

2001年NOI全国竞赛

 时间限制: 5 s
 空间限制: 64000 KB
 
 
题目描述 Description

已知一个n元高次方程:

k1x1p1+k2x2p2+……+knxnpn = 0

其中:x1, x2, …,xn是未知数,k1,k2,…,kn是系数,p1,p2,…pn是指数。且方程中的所有数均为整数。

假设未知数1≤ xi ≤M, i=1,,,n,求这个方程的整数解的个数。

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

3

150

1  2

-1  2

1  2

样例输出 Sample Output

178

数据范围及提示 Data Size & Hint

 1≤n≤6;1≤M≤150;

|k1Mp1|+|k2Mp2|+……+|knMpn |< 231

方程的整数解的个数小于231。

★本题中,指数Pi(i=1,2,……,n)均为正整数。

练一下meet in the middle

暴力搜索:150 ^ 6 =11390625000000

meet in the middle :150 ^3  =3375000

计算满足 a+b+c+d+e+f=0  的数的个数

可以算 (a+b+c)+ (d+e+f) = 0

dfs两次,每次dfs一半

结果用双指针逼近法、乘法原理 O(n) 处理

#include<cstdio>
#include<algorithm>
#include<iostream>
#define N 3875000
using namespace std;
int n,m,half,nod,ans;
int k[10],p[10];
int tmp1[N+1],sum1,tmp2[N+1],sum2; 
int qm(int a,int q)
{
    int b=1;
    for(;q;a*=a,q>>=1)
     if(q & 1) b*=a;
    return b;
}
void dfs(int now,int tot,int *tmp,int & sum)
{
    if(now>nod) { tmp[++sum]=tot; return; }
    for(int i=1;i<=m;i++) dfs(now+1,tot+k[now]*qm(i,p[now]),tmp,sum); 
}
void work()
{
    int cnt1,cnt2,j=sum2;
    sort(tmp1+1,tmp1+sum1+1);
    sort(tmp2+1,tmp2+sum2+1);
    for(int i=1;i<=sum1;i++)
    {
        while(j && tmp1[i]+tmp2[j]>0) --j;
        if(!j) break;
        if(!(tmp1[i]+tmp2[j]))
        {
            cnt1=1,cnt2=1;
            while(i<sum1 && tmp1[i+1]==tmp1[i]) cnt1++,i++;
            while(j>1 && tmp2[j-1]==tmp2[j]) cnt2++,j--;
            ans+=cnt1*cnt2;
        }
    }
}
int main()
{
    freopen("equation1.in","r",stdin);
    freopen("equation1.out","w",stdout);
    scanf("%d%d",&n,&m);
    half=n>>1;
    for(int i=1;i<=n;i++) scanf("%d%d",&k[i],&p[i]);
    nod=half;
    dfs(1,0,tmp1,sum1);
    nod=n;
    dfs(half+1,0,tmp2,sum2);
    work();
    printf("%d",ans);
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7267335.html