P5598【XR-4】混乱度

卢卡斯定理优化

P5598【XR-4】混乱度

题目描述

小 X 有 nn 种颜色的球,其中第 ii 种颜色的球共有 aia_i 个,同色的球无法区分。定义第 lrl \sim r 种颜色的混乱度 f(l,r)f(l, r) 为:将第 lrl \sim r 种颜色的所有球排成一排,总共的方案数对 pp 取模后的值。小 X 想请你帮忙计算下列式子的值:

l=1nr=lnf(l,r)\sum_{l=1}^n \sum_{r=l}^n f(l, r)

题目分析

一眼就看出来f是一个可重集合的排列,而且计算很快,困难的是a的值域太大了,一般的卢卡斯定理还不能通过此题。所以要进行预处理来加快卢卡斯定理的计算速度。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//
// Created by mrx on 2022/10/6.
//

#include <vector>
#include <algorithm>
#include <iostream>
#include <array>

using ll = long long;
int P = 1;

struct digit {
std::vector<int> d;
int cnt;

digit() : d(10), cnt(0) {}

digit(ll x) : d(10), cnt(0) {
ll tmp = x;
while (tmp) {
d[cnt++] = tmp % P;
tmp /= P;
}
}

void add(const digit& rhs) {
for (int i = 0; i < std::max(cnt, rhs.cnt); i++) {
d[i] += rhs.d[i];
if (d[i] >= P) {
d[i] -= P;
d[i + 1]++;
}
}
}
};


int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int n, p;
std::cin >> n >> p;
P = 1;
while (P < 5000)P *= p;
P /= p;
std::vector<std::vector<int>> C(P + 1, std::vector<int>(P + 1));
C[0][0] = 1;
for (int i = 1; i <= P; ++i) {
C[i][0] = C[i][i] = 1;
for (int j = 1; j < P; ++j) {
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % p;
}
}
auto lucas = [&](const digit& n, const digit& m) {
int s = 1;
for (int i = 0; i < m.cnt; ++i) {
s *= C[n.d[i]][m.d[i]] %= p;
}
return s;
};
std::vector<digit> a(n + 1);
for (int i = 0; i < n; ++i) {
ll x;
std::cin >> x;
a[i] = digit(x);
}

std::vector<int> r(n + 1);
a[n].cnt = 1;
int st = 0;
for (int i = 0; i <= n; i++) {
if (a[i].cnt) {
for (int j = i - 1; j >= st; j--)r[j] = i;
st = i;
}
}

ll ans = 0;
for (int i = 0; i < n; ++i) {
int ptr = i;
digit tmp = a[ptr];
int cur = 1;
while (cur && ptr < n) {
ans += (r[ptr] - ptr) * cur;
ptr = r[ptr];
tmp.add(a[ptr]);
cur *= lucas(tmp, a[ptr]);
cur %= p;
}
}
std::cout << ans << '\n';
return 0;
}

P5598【XR-4】混乱度
https://mrxyan6.github.io/2022/10/13/P5598/
作者
mrx
发布于
2022年10月13日
许可协议