PSequence
题目描述
给定一个元素集合 SSS,求 SSS 的所有排列满足对于任意相邻两个元素 s1s_1s1,s2s_2s2,(s1−s2)(s_1−s_2)(s1−s2) 不被 P 整除。保证 SSS 中任意两个元素都不相同。
输入格式
输入第一行一个数 nnn,表示集合 SSS 的大小
以下 nnn 个数
最后一个数 PPP
n
s1 s2 ... sn
P
输出格式
输出一个数,表述满足条件的排列的个数,模 123456789112345678911234567891。
样例
input #1
4
1 2 3 4
3
output #1
12
数据范围及提示
对于 30%30\%30% 的数据,n≤9n\leq 9n≤9
对于 100%100\%100% 的数据,n≤30n\leq 30n≤30,Si≤106S_i\leq 10^6Si≤106
注明
转载需经过本人同意。转载需经过本人同意。转载需经过本人同意。
解题思路
首先,若 sis_isi、si+1s_{i+1}si+1 如果不符合条件,则 s1s_1s1、s2s_2s2 模 ppp 同。那么你用 CCC 数组可以记下 SSS 内所有元素的值模 ppp 等于的各个数的个数,从大到小排序。设要在原序列选 kkk 个不合法,lll 个合法的的位置插入,设 Fi,jF_{i,j}Fi,j 表示处理了前 iii 大的余数的数,有 jjj 对不合法的方案数的方案数。不难推出:
Fi,j−k+Ci−k−1+=Fi−1,j×Cjk×Cs+1−jl×Cc−1k+l−1
F_{i,j-k+C_i-k-1}+=F_{i-1,j}\times C_j^k\times C_{s+1-j}^l\times C_{c-1}^{k+l-1}
Fi,j−k+Ci−k−1+=Fi−1,j×Cjk×Cs+1−jl×Cc−1k+l−1
当枚举到 CCC 数组的值为 000 时,答案就为:Fi−1,0×ΠCi!F_{i-1,0}\times \Pi C_i!Fi−1,0×ΠCi!
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int Maxn = 30 + 5, Maxval = 1e6 + 5, Mod = 1234567891;
int Fac[Maxn], InFac[Maxn];
inline int Q_Pow(int x, int y) {
int res = 1;
while (y) {
if (y & 1)
res = res * x % Mod;
x = x * x % Mod;
y >>= 1;
}
return res;
}
inline int Get_C(int a, int b) {
if (b > a || a < 0 || b < 0)
return 0;
return Fac[a] * InFac[b] % Mod * InFac[a - b] % Mod;
}
int n, s[Maxn], p;
map<int, int>Map;
int C[Maxval], Top, F[Maxn][Maxn];
int Answer;
inline bool Cmp(int a, int b) {
return a > b;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
Fac[0] = 1;
InFac[0] = 1;
for (register int i = 1; i < Maxn; ++i) {
Fac[i] = Fac[i - 1] * i % Mod;
InFac[i] = InFac[i - 1] * Q_Pow(i, Mod - 2) % Mod;
}
cin >> n;
for (register int i = 1; i <= n; ++i)
cin >> s[i];
cin >> p;
for (register int i = 1; i <= n; ++i)
++Map[(s[i] % p + p) % p];
for (auto [x, y] : Map)
C[Top++] = y;
sort(C, C + Top, Cmp);
F[0][C[0] - 1] = 1;
for (register int i = 1, s = C[0]; i <= n; ++i) {
if (C[i] == 0) {
for (register int j = 0; j < Top; ++j)
(F[i - 1][0] *= Fac[C[j]]) %= Mod;
cout << F[i - 1][0] << endl;
exit(0);
}
for (register int j = 0; j <= s; ++j)
for (register int k = 0; k <= C[i]; ++k)
for (register int l = 0; l <= C[i]; ++l)
if (j - k + C[i] - k - l >= 0)
(F[i][j - k + C[i] - k - l] += F[i - 1][j] * Get_C(j, k) % Mod * Get_C(s + 1 - j, l) % Mod * Get_C(C[i] - 1, k + l - 1) % Mod) %= Mod;
s += C[i];
}
return 0;
}
然后你就秒了。

280

被折叠的 条评论
为什么被折叠?



