2010-1102
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
== 题意 ==
求满足以下两个条件,长度为n的b进制数的个数分别是多少
1. x移除s~t(3<=s<=t<=n)位之间的某一位得到y,使得x % y == 0
1. x移除最左边的一位得到y,使得x % y == 0
== 思路 ==
=== 第一问 ===
对于第一问,我们可以证明必然有 x = by,否则必然存在 x = ky (k >= b + 1 或 k <= b - 1),设x = a,,0,,b^0^ + a,,1,,b^1^ + ... + a,,n-1,,b^n-1^ ,则 y = a,,0,,b^0^ + a,,1,,b^1^ + ... + a,,n-k-1,,b^n-k-1^ + a,,n-k+1,,b^n-k^ + ... + a,,n-1,,b^n-2^ ,若k = b + 1, 则by = a,,0,,b^0^ + (a,,0,, + a,,1,,)b^1^ + ... + (a,,n-k-2,, + a,,n-k-1,,)b^n-k-1^ + (a,,n-k-1,, + a,,n-k+1,,)b^n-k^ + ... + '''(a,,n-2,, + a,,n-1,,)b^n-2^''' + a,,n-1,,b^n-1^,x中和by中,b^n-1^的系数都是a,,n-1,,,于是看b^n-2^的系数,x中这一项的系数是a,,n-2,,而by中这一项的系数是(a,,n-2,, + a,,n-1,,) > a,,n-2,,,所以 by > x,同理也可以得出当k <= b - 1时 by < x,所以k只有等于b这一种可能。
有了这个结论,剩下的就简单了,比对下by和x,就可以得出a,,0,, = a,,1,, = ... = a,,n-k,, = 0 这个结论,于是第一种情况的答案就是(b-1) * b^(t-2)。
=== 第二问 ===
对于第二问,a,,n-1,, * b^n-1^ = k * (a,,n-2,,b^n-2^ + ... + a,,0,,),于是就是求将a,,n-1,,b^n-1^分解成两个数的乘积,并且两数都小于b^n-1^的方方案数,所有的分解方案减去其一个数大于等于b^n-1^的方案就可以了。
== 代码 ==
from shi哥
{{{
#!java
import java.math.*;
import java.util.*;
public class Main {
static final int[] pl = new int[]{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
static final int pn = pl.length;
static final int[][] ps = new int[33][pn];
static {
for (int i = 1; i < ps.length; ++i) {
for (int j = 0; j < pl.length; ++j) {
int k = i;
while (k % pl[j] == 0) {
++ps[i][j];
k /= pl[j];
}
}
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextInt()) {
int n = in.nextInt();
int b = in.nextInt();
int s = in.nextInt();
int t = in.nextInt();
System.out.print(BigInteger.valueOf(b).pow(t - 2).multiply(BigInteger.valueOf(b - 1)));
BigInteger ans = BigInteger.ZERO;
for (int i = 1; i < b; ++i) {
int[] a = new int[pn];
BigInteger tmp = BigInteger.ONE;
for (int j = 0; j < pn; ++j) {
a[j] = ps[i][j] + ps[b][j] * (n - 1);
tmp = tmp.multiply(BigInteger.valueOf(a[j] + 1));
}
int dif = i;
for (int k = 1; k <= i; ++k) {
for (int j = 0; j < pn; ++j) {
if (ps[k][j] > a[j]) {
--dif;
break;
}
}
}
ans = ans.add(tmp.subtract(BigInteger.valueOf(dif)));
}
System.out.println(" " + ans);
}
}
}
}}}
题意
求满足以下两个条件,长度为n的b进制数的个数分别是多少
1. x移除s~t(3<=s<=t<=n)位之间的某一位得到y,使得x % y == 0
1. x移除最左边的一位得到y,使得x % y == 0
思路
第一问
对于第一问,我们可以证明必然有 x = by,否则必然存在 x = ky (k >= b + 1 或 k <= b - 1),设x = a0b0 + a1b1 + ... + an-1bn-1 ,则 y = a0b0 + a1b1 + ... + an-k-1bn-k-1 + an-k+1bn-k + ... + an-1bn-2 ,若k = b + 1, 则by = a0b0 + (a0 + a1)b1 + ... + (an-k-2 + an-k-1)bn-k-1 + (an-k-1 + an-k+1)bn-k + ... + (an-2 + an-1)bn-2 + an-1bn-1,x中和by中,bn-1的系数都是an-1,于是看bn-2的系数,x中这一项的系数是an-2而by中这一项的系数是(an-2 + an-1) > an-2,所以 by > x,同理也可以得出当k <= b - 1时 by < x,所以k只有等于b这一种可能。
有了这个结论,剩下的就简单了,比对下by和x,就可以得出a0 = a1 = ... = an-k = 0 这个结论,于是第一种情况的答案就是(b-1) * b^(t-2)。
第二问
对于第二问,an-1 * bn-1 = k * (an-2bn-2 + ... + a0),于是就是求将an-1bn-1分解成两个数的乘积,并且两数都小于bn-1的方方案数,所有的分解方案减去其一个数大于等于bn-1的方案就可以了。
代码
from shi哥
import java.math.*;
import java.util.*;
public class Main {
static final int[] pl = new int[]{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
static final int pn = pl.length;
static final int[][] ps = new int[33][pn];
static {
for (int i = 1; i < ps.length; ++i) {
for (int j = 0; j < pl.length; ++j) {
int k = i;
while (k % pl[j] == 0) {
++ps[i][j];
k /= pl[j];
}
}
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextInt()) {
int n = in.nextInt();
int b = in.nextInt();
int s = in.nextInt();
int t = in.nextInt();
System.out.print(BigInteger.valueOf(b).pow(t - 2).multiply(BigInteger.valueOf(b - 1)));
BigInteger ans = BigInteger.ZERO;
for (int i = 1; i < b; ++i) {
int[] a = new int[pn];
BigInteger tmp = BigInteger.ONE;
for (int j = 0; j < pn; ++j) {
a[j] = ps[i][j] + ps[b][j] * (n - 1);
tmp = tmp.multiply(BigInteger.valueOf(a[j] + 1));
}
int dif = i;
for (int k = 1; k <= i; ++k) {
for (int j = 0; j < pn; ++j) {
if (ps[k][j] > a[j]) {
--dif;
break;
}
}
}
ans = ans.add(tmp.subtract(BigInteger.valueOf(dif)));
}
System.out.println(" " + ans);
}
}
}