Address
洛谷 P3286
BZOJ 3598
LOJ #2215
Solution
- NOIP 2018 后的第一篇博文,一个新的开始
- 众所周知,数轴上有一个点集,求一个点到这些点的距离之和最小
- 则这个点的坐标是这些点的坐标的中位数
- 而此题显然是一个数位 DP
- 询问拆成
[0,R] 和
[0,L−1]
- 下面只讨论
[0,R]
- 定义状态(下面的「位」都是从低到高)
-
f[i][j][0/1/2] 表示第
1 位到第
i 位,用的数字之和为
j ,小于 / 等于 / 大于
R 的第
1 位到第
i 位的方案数
-
fc[i][j][0/1/2] 表示第
1 位到第
i 位,用的数字之和为
j ,小于 / 等于 / 大于
R 的第
1 位到第
i 位的所有数的数字之和
-
g[i][j][0/1/2] 表示第
i 位到第
m 位,用的数字之和为
j ,小于 / 等于 / 大于
R 的第
i 位到第
m 位的方案数
-
gc[i][j][0/1/2] 表示第
i 位到第
m 位,用的数字之和为
j ,小于 / 等于 / 大于
R 的第
i 位到第
m 位的所有数的数字之和
-
m 为
R 的位数
- 大力转移
- 统计
[0,R] 的结果时,考虑枚举中位数所在的位置
i 和位置
i 的值
j
- 注意,
j 不能等于
0
- 然后枚举比
i 低的位的数字之和
k
- 还有比
i 高的位的数字之和
h
- 通过
k 、
h 、
j 判断中位数是否在
i 位置
- 再用
g(c)[i+1][h][0/1/2] 和
f(c)[i−1][k][0/1/2] 统计答案
- 注意需要根据具体情况决定第三维下标
0/1/2 是否可以使用
- 并特判
i=m 和
i=1 的情况
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
typedef long long ll;
const int N = 70, M = 250;
ll L, R, f[N][M][3], g[N][M][3], fc[N][M][3], gc[N][M][3];
int K, tot, a[N];
ll jiejuediao(ll n)
{
if (n < K) return 0;
tot = 0;
while (n) a[++tot] = n % K, n /= K;
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(f));
memset(fc, 0, sizeof(fc));
memset(gc, 0, sizeof(gc));
int i, j, k, h, o1, o2, m = tot * (K - 1);
ll ans = 0;
For (i, 0, K - 1)
{
int op = i > a[1] ? 2 : (i == a[1] ? 1 : 0);
f[1][i][op]++; fc[1][i][op] += i;
op = i > a[tot] ? 2 : (i == a[tot] ? 1 : 0);
g[tot][i][op]++; gc[tot][i][op] += i * tot;
}
For (i, 2, tot) For (j, 0, m) For (k, 0, K - 1)
{
if (k > j) break;
if (k < a[i])
{
f[i][j][0] += f[i - 1][j - k][0] + f[i - 1][j - k][1]
+ f[i - 1][j - k][2];
fc[i][j][0] += fc[i - 1][j - k][0] + fc[i - 1][j - k][1]
+ fc[i - 1][j - k][2] + (f[i - 1][j - k][0]
+ f[i - 1][j - k][1] + f[i - 1][j - k][2]) * i * k;
}
else if (k > a[i])
{
f[i][j][2] += f[i - 1][j - k][0] + f[i - 1][j - k][1]
+ f[i - 1][j - k][2];
fc[i][j][2] += fc[i - 1][j - k][0] + fc[i - 1][j - k][1]
+ fc[i - 1][j - k][2] + (f[i - 1][j - k][0]
+ f[i - 1][j - k][1] + f[i - 1][j - k][2]) * i * k;
}
else
{
f[i][j][0] += f[i - 1][j - k][0];
fc[i][j][0] += fc[i - 1][j - k][0] + f[i - 1][j - k][0] * i * k;
f[i][j][1] += f[i - 1][j - k][1];
fc[i][j][1] += fc[i - 1][j - k][1] + f[i - 1][j - k][1] * i * k;
f[i][j][2] += f[i - 1][j - k][2];
fc[i][j][2] += fc[i - 1][j - k][2] + f[i - 1][j - k][2] * i * k;
}
}
Rof (i, tot - 1, 1) For (j, 0, m) For (k, 0, K - 1)
{
if (k > j) break;
if (k < a[i])
{
g[i][j][0] += g[i + 1][j - k][0] + g[i + 1][j - k][1];
g[i][j][2] += g[i + 1][j - k][2];
gc[i][j][0] += gc[i + 1][j - k][0] + gc[i + 1][j - k][1]
+ (g[i + 1][j - k][0] + g[i + 1][j - k][1]) * i * k;
gc[i][j][2] += gc[i + 1][j - k][2] + g[i + 1][j - k][2] * i * k;
}
else if (k > a[i])
{
g[i][j][0] += g[i + 1][j - k][0];
g[i][j][2] += g[i + 1][j - k][1] + g[i + 1][j - k][2];
gc[i][j][0] += gc[i + 1][j - k][0] + g[i + 1][j - k][0] * i * k;
gc[i][j][2] += gc[i + 1][j - k][1] + gc[i + 1][j - k][2]
+ (g[i + 1][j - k][1] + g[i + 1][j - k][2]) * i * k;
}
else
{
g[i][j][0] += g[i + 1][j - k][0];
gc[i][j][0] += gc[i + 1][j - k][0] + g[i + 1][j - k][0] * i * k;
g[i][j][1] += g[i + 1][j - k][1];
gc[i][j][1] += gc[i + 1][j - k][1] + g[i + 1][j - k][1] * i * k;
g[i][j][2] += g[i + 1][j - k][2];
gc[i][j][2] += gc[i + 1][j - k][2] + g[i + 1][j - k][2] * i * k;
}
}
For (i, 1, tot) For (j, 1, K - 1) For (k, 0, m) For (h, 0, m)
{
int mid = (k + j + h >> 1) + 1;
if (k + 1 > mid || mid > k + j) continue;
if ((i == tot && k) || (i == 1 && h)) continue;
if (i == tot) For (o1, 0, 2)
{
if ((j == a[i] && o1 == 2) || j > a[i]) continue;
ans += f[tot - 1][h][o1] * i * h - fc[tot - 1][h][o1];
}
if (i == 1) For (o2, 0, 1)
{
if (o2 == 1 && j > a[i]) continue;
ans += gc[2][k][o2] - g[2][k][o2] * i * k;
}
if (1 < i && i < tot) For (o1, 0, 2) For (o2, 0, 1)
{
if (o2 == 1 && (j > a[i] || (j == a[i] && o1 == 2))) continue;
ans += (f[i - 1][h][o1] * i * h - fc[i - 1][h][o1])
* g[i + 1][k][o2];
ans += (gc[i + 1][k][o2] - g[i + 1][k][o2] * i * k)
* f[i - 1][h][o1];
}
}
return ans;
}
int main()
{
std::cin >> L >> R >> K;
std::cout << jiejuediao(R) - jiejuediao(L - 1) << std::endl;
return 0;
}