[NOI2001] 方程的解数
题目描述
已知一个
n
n
n 元高次方程:
∑
i
=
1
n
k
i
x
i
p
i
=
0
\sum\limits_{i=1}^n k_ix_i^{p_i} = 0
i=1∑nkixipi=0
其中:
x
1
,
x
2
,
…
,
x
n
x_1, x_2, \dots ,x_n
x1,x2,…,xn 是未知数,
k
1
,
k
2
,
…
,
k
n
k_1,k_2, \dots ,k_n
k1,k2,…,kn 是系数,
p
1
,
p
2
,
…
p
n
p_1,p_2,…p_n
p1,p2,…pn 是指数。且方程中的所有数均为整数。
假设未知数 x i ∈ [ 1 , m ] ( i ∈ [ 1 , n ] ) x_i \in [1,m] \space ( i \in [1,n]) xi∈[1,m] (i∈[1,n]),求这个方程的整数解的个数。
输入格式
第一行一个正整数
n
n
n,表示未知数个数。
第二行一个正整数
m
m
m。
接下来
n
n
n 行,每行两个整数
k
i
,
p
i
k_i,p_i
ki,pi。
输出格式
输出一行一个整数,表示方程解的个数。
样例 #1
样例输入 #1
3
150
1 2
-1 2
1 2
样例输出 #1
178
提示
【数据范围】
对于
100
%
100\%
100% 的数据,
1
≤
n
≤
6
1\le n \le 6
1≤n≤6,
1
≤
m
≤
150
1\le m \le 150
1≤m≤150,且
∑
i
=
1
n
∣
k
i
m
p
i
∣
<
2
31
\sum\limits_{i=1}^n |k_im^{p_i}| < 2^{31}
i=1∑n∣kimpi∣<231
答案不超过
2
31
−
1
2^{31}-1
231−1,
p
i
∈
N
∗
p_i \in \mathbb N^*
pi∈N∗。
思路
- 我们首先看到 n n n 很小,因此我们想到爆搜,为此,我们会写出如下代码:
30 p t s 30\ pts 30 pts
//未知数的数量很小,我们试着dfs
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define int long long
const int N = 8;
int k[N],p[N];
int n,m;
int ans;
void dfs(int u,int s){
if(u==n+1){
if(s==0) ans++;
return;
}
for(int i=1;i<=m;i++){
int t=k[u]*pow(i,p[u]);
dfs(u+1,s+t);
}
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>k[i]>>p[i];
}
dfs(1,0);
cout<<ans;
return 0;
}
- 因此,我们考虑优化,我们尝试折半搜索。为什么呢?因为我们发现如果直接搜索的话,且 dfs 的时间复杂度是指数级别的,如果我们折半搜索,能把指数大部分的装化成指数的系数。
- 折半搜索都是
dfs1
来搜索,搜到的答案记录到 w w w 数组中,然后dfs2
把这些内容取出来且看看与 w w w 数组中有多少个相同的就行了。 - 但我们存入答案要取出的东西是什么呢?我们把原问题的式子拆成
∑
i
=
1
⌊
n
/
2
⌋
k
i
∗
x
i
p
i
=
−
∑
⌈
n
/
2
⌉
k
i
∗
x
i
p
i
\sum_{i=1}^{\lfloor{n/2}\rfloor}k_i*x_i^{p_i}=-\sum_{\lceil{n/2}\rceil}k_i*x_i^{p_i}
∑i=1⌊n/2⌋ki∗xipi=−∑⌈n/2⌉ki∗xipi,因此我们
dfs2
就得找-s
,因为这个式子是负的。 - 这边取出的时候我们是看有多少个相同的,此时就得用
upper_bound
和lower_bound
合起来算。
AC 代码
//未知数的数量很小,我们试着dfs
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define int long long
const int N = 10,M = 1e7+10;
int k[N],p[N];
int n,m;
int ans,tmp;
int w[M],cnt;
// void dfs(int u,int s){
// if(u==n+1){
// if(s==0) ans++;
// return;
// }
// for(int i=1;i<=m;i++){
// int t=k[u]*pow(i,p[u]);
// dfs(u+1,s+t);
// }
// }
void dfs1(int u,int s){
if(u==tmp){
w[++cnt]=s;
return;
}
for(int i=1;i<=m;i++){
dfs1(u+1,s+pow(i,p[u])*k[u]);
}
}
void dfs2(int u,int s){
if(u==n+1){
int k=upper_bound(w+1,w+1+cnt,-s)-lower_bound(w+1,w+1+cnt,-s);
ans+=k;
return;
}
for(int i=1;i<=m;i++){
dfs2(u+1,s+pow(i,p[u])*k[u]);
}
}
signed main(){
cin>>n>>m;
tmp=(n>>1)+1;
for(int i=1;i<=n;i++){
cin>>k[i]>>p[i];
}
dfs1(1,0);
sort(w+1,w+1+cnt);
dfs2(tmp,0);
cout<<ans;
return 0;
}