Description
已知一个n元高次方程:
其中:x1, x2,...,xn是未知数,k1,k2,...,kn是系数,p1,p2,...pn是指数。且方程中的所有数均为整数。
假设未知数1 <= xi <= M, i=1,,,n,求这个方程的整数解的个数。
1 <= n <= 6;1 <= M <= 150。
方程的整数解的个数小于231。
★本题中,指数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
分析
首先考虑暴力解法
搜索树一共六层,每层枚举1 ~ 150作为解
这样下来状态数就是150 ^ 6 = 11390625000000
实在是太过庞大
所以考虑meet in the middle 优化
这样一来状态数就变成了150 ^ 3 = 3375000
这道题就可以做了
我们把式子分为前半段和后半段分别处理出所有值
然后统计所有两段之和为0的方案数
双指针扫描法(自己起的名字。嘿嘿嘿)
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n, m;
int k[17], p[17];
int a[4000010], b[4000010];
int cnta, cntb;
long long ans;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return x * f;
}
int pow(int aa, int bb) {
int mul = 1;
while (bb) {
if (bb & 1) mul *= aa;
aa *= aa;
bb >>= 1;
}
return mul;
}
void dfs1(int dep, int sum) {
if (dep > n / 2) {
a[++cnta] = sum;
return;
}
for (int i = 1; i <= m; i++) dfs1(dep + 1, sum + k[dep] * pow(i, p[dep]));
}
void dfs2(int dep, int sum) {
if (dep > n) {
b[++cntb] = sum;
return;
}
for (int i = 1; i <= m; i++) dfs2(dep + 1, sum + k[dep] * pow(i, p[dep]));
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++) k[i] = read(), p[i] = read();
dfs1(1, 0);
dfs2(n / 2 + 1, 0);
int j = cntb;
sort(a + 1, a + cnta + 1);
sort(b + 1, b + cntb + 1);
for (int i = 1; i <= cnta; i++) {
while (j && a[i] + b[j] > 0) j--;
if (!j) break;
if (a[i] + b[j] == 0) {
int ca = 1, cb = 1;
while (i < cnta && a[i] == a[i + 1]) ca++, i++;
while (j > 1 && b[j] == b[j - 1]) cb++, j--;
ans += ca * cb;
}
}
printf("%lld", ans);
}