⭐ 简单分治(过样例)
① 算出 数 n 最后 划分 的 0 1 序列的长度(找规律)
② 划分的三个数 中间的数 肯定是 0 / 1 ,直接在区间中点记录结果
③ 递归处理左右区间,直到区间左右边界重合,也就是 0 1 已经放满了,此时的 x 就是结果该位置的 结果了
import java.util.Scanner;
public class 数的拆分
{
static int N = (int) 1e8;
static int[] a = new int[N];
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int l = sc.nextInt();
int r = sc.nextInt();
int cnt = 0;// 记录 n 可以分出多少层
for (int i = 0; i < 55; i++)
if (n >= (1 << i) && n < (1 << i + 1))
{
cnt = i;
break;
}
// System.out.println(cnt);
int sum = 0;// sum 记录n 划分后的序列长度
for (int i = 0; i <= cnt; i++)
sum = sum * 2 + 1;
mergeSort(n, 1, sum);
long res = 0;
for (int i = l; i <= r; i++)
if (a[i] == 1)
res++;
System.out.println(res);
}
private static void mergeSort(int x, int l, int r)
{
if (l == r)
{
a[l] = x;
return;
}
int t = x / 2;
int m = x % 2;// m 不是 0 就是 1,所以直接放入数组即可
int mid = l + r >> 1;
a[mid] = m;
// 递归处理左右区间
mergeSort(t, l, mid - 1);
mergeSort(t, mid + 1, r);
}
}
⭐ 剪枝 + 下标映射
package algorithm.lanQiao.分治;
import java.util.Scanner;
public class 数的拆分
{
static int N = (int) 1e8;
static Long L, R;
static int[] a = new int[N];
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
L = sc.nextLong();
R = sc.nextLong();
int cnt = 0;// 记录 n 可以分出多少层
for (int i = 0; i < 51; i++)
if (n >= (1 << i) && n < (1 << i + 1))
{
cnt = i;
break;
}
// System.out.println(cnt);
int sum = 0;// sum 记录n 划分后的序列长度
for (int i = 0; i <= cnt; i++)
sum = sum * 2 + 1;
mergeSort(n, 1, sum);
long res = 0;
for (int i = 0; i <= R - L + 1; i++)
{
// System.out.print(a[i] + " ");
if (a[i] == 1)
res++;
}
System.out.println(res);
}
private static void mergeSort(int x, int l, int r)
{
// 非需要求解的区间(剪枝)
int mid = l + r >> 1;
if (l > R || r < L)
{
return;
}
if (l == r)
{
a[(int) (l - L + 1)] = x;
return;
}
int t = x / 2;
int m = x % 2;// m 不是 0 就是 1,所以直接放入数组即可
a[(int) (mid - L) + 1] = m;
// 递归左右区间
mergeSort(t, l, mid - 1);
mergeSort(t, mid + 1, r);
}
}