x+2y=10的非负整数解的个数------①
我们直观的看(x,y)的取值有:(0,5),(2,4),(4,3)等。那么从组合数学的角度来讲,我们要怎么思考呢x可能的取值0,1,2,3...y同样的取值也是如此。根据组合数学的思想,x的所有情况乘以y的所有情况,得到的就是真个解得所有的个数。将这个思想表示为如下的公式:
(1 + x + x^2 + x^3+...)(1 + x^2 + x^4 + x^6 +...)------②
第一个括号中,1表示x取0,x表示x取1,x^2表示x取2,依此类推。第二个括号中,x^2表示y取1(2 = 1 * 2),x^4表示y取2(4 = 2 * 2),依此类推。可得。通过观察,我们可以得到,②括号中指数,就表示①中的直,比如x^4中的4就是y取2的时候,即2*y的值。那么,我们展开②式,ax^b的意义就是 x + 2y = b 的非负整数解得个数为a。
杭电ACM的1028,1398,1171都是关于母函数的。而且都是相对比较基础的题目。只要能够将母函数的表示出来,找到系数和指数的含义,就能够顺利的解出题目。稍后简单分析一下几个题目。
- 1028题
import java.util.Scanner; public class P1028 { public static void main(String[] args) { int[] c1 = new int[121]; int[] c2 = new int[121]; Scanner in = new Scanner(System.in); while (in.hasNextInt()) { int n = in.nextInt(); for (int i = 0; i <= n; ++i) { c1[i] = 1; c2[i] = 0; } for (int i = 2; i <= n; ++i) { for (int j = 0; j <= n; ++j) for (int k = 0; k <= n; k += i) c2[k + j] += c1[j]; for (int j = 0; j <= n; ++j) { c1[j] = c2[j]; c2[j] = 0; } } System.out.println(c1[n]); } } }
- 1398题
import java.util.Scanner; public class P1398 { private static int[] coinType = new int[18]; static { for (int i = 1; i < 18; ++i) coinType[i] = i * i; } public static void main(String[] args) { int[] c1 = new int[301]; int[] c2 = new int[301]; Scanner in = new Scanner(System.in); while (in.hasNextInt()) { int n = in.nextInt(); if (0 == n) return; for (int i = 0; i <= n; ++i) { c1[i] = 1; c2[i] = 0; } for (int i = 2; i < 18; ++i) { for (int j = 0; j <= n; ++j) for (int k = 0; k + j <= n; k += coinType[i]) c2[k + j] += c1[j]; for (int j = 0; j <= n; ++j) { c1[j] = c2[j]; c2[j] = 0; } } System.out.println(c1[n]); } } }
- 1171题
import java.util.Arrays; import java.util.Scanner; public class P1171 { public static void main(String[] args) { int[] c1 = new int[250001]; int[] c2 = new int[250001]; Scanner in = new Scanner(System.in); while (in.hasNextLine()) { int n = Integer.parseInt(in.nextLine()); if (n < 0) return; int[] v = new int[n + 1]; int[] m = new int[n + 1]; int sum = 0; for (int i = 1; i <= n; ++i) { String[] ss = in.nextLine().split("[ ]+"); v[i] = Integer.parseInt(ss[0]); m[i] = Integer.parseInt(ss[1]); sum += v[i] * m[i]; } Arrays.fill(c1, 0); Arrays.fill(c2, 0); for (int i = 0; i <= v[1] * m[1]; i += v[1]) c1[i] = 1; int len = v[1] * m[1]; for (int i = 2; i <= n; ++i) { for (int j = 0; j <= len; ++j) for (int k = 0; k <= v[i] * m[i]; k += v[i]) c2[k + j] += c1[j]; len += v[i] * m[i]; for (int j = 0; j <= len; ++j) { c1[j] = c2[j]; c2[j] = 0; } } for(int i= sum / 2; i >= 0; --i) if(c1[i] != 0) { System.out.println((sum - i) + " " + i); break; } } } }