# T1、Count

## $Sol$：

$A = \sum_{i = 1}^{k} a_i \ mod \ m \equiv n \ mod \ m$，由于 $a_i \ mod \ m$ 不会超过 $m - 1$，所以 $\sum_{i = 1} ^ k a_i$ 不会超过 $k (m - 1)$，那么 $A$ 最多有 $k$ 中取值，不妨枚举这 $k$$A$。这样一来就有 $(n - A) / m$$m$ 可以随机分配，这个可以用隔板法计算；对于 $A$ 的分配可以枚举有多少数大于 $m - 1$ 来容斥。

## $Source$：

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
ll lin() {
ll x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 1e7 + 5, mod = 998244353;

ll n;
int m, k, fac[N], inv[N];

int qpow(int base, int b, int ret = 1) {
for (; b; b >>= 1, base = 1ll * base * base % mod)
if (b & 1)
ret = 1ll * ret * base % mod;
return ret;
}

void prep() {
fac[0] = inv[0] = 1;
for (int i = 1; i < N; ++i)
fac[i] = 1ll * fac[i - 1] * i % mod;
inv[N - 1] = qpow(fac[N - 1], mod - 2);
for (int i = N - 2; i; --i)
inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
}

inline int C(const int n, const int m) {
if (n < m)
return 0;
return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;
}

int calc(int A) {
int ret = 0, lim = std::min(A / (m - 1), k);
for (int i = 0; i <= lim; ++i) {
ret += (i & 1 ? -1ll : 1ll) * C(k, i) * C(A - i * (m - 1) - 1, k - 1) % mod;
if (ret >= mod)
ret -= mod;
if (ret < 0)
ret += mod;
}
return ret;
}

int work() {
int ret = 0, tmp;
for (int A = n % m; A <= n && A <= k * (m - 1); A += m) {
tmp = inv[k - 1];
for (ll i = (n - A) / m + k - 1; i >= (n - A) / m + 1; --i)
tmp = i % mod * tmp % mod;
ret += 1ll * tmp * calc(A) % mod;
if (ret >= mod)
ret -= mod;
}
return ret;
}

int main() {
//freopen("in", "r", stdin);
freopen("count.in", "r", stdin);
freopen("count.out", "w", stdout);
n = lin(), m = in(), k = in();
prep();
printf("%d\n", work());
return 0;
}


# T2、普及组

1、矩阵里的数都是整数；
2、$\forall j, \prod_{i = 1} ^ n a_{i , j} = x$
3、$\forall j, \prod_{i = 1} ^ n a_{j , i} = x$

## $Sol$：

$f_i , g_i$ 表示 $i \times i$ 的矩阵中最后一列填了两个 $1$ 或一个 $2$ 的方案数。

$g$ 的转移是显然的：

$g_i = (f_{i - 1} + g_{i - 1}) \times i$

$f$ 的转移可以考虑 $i \times i$ 的矩阵中删掉一列一行 (不妨设是最后一列)：

$f_i = \binom{i}{2} \times (2 f_{i - 1} + g_{i - 1})$

## $Source$：

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
typedef long long ll;
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
ll lin() {
ll x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 5e6 + 5, mod = 998244353;

ll x;
int T, n, f[N], g[N], fac[N], cnt[3];

int qpow(int base, int b, int ret = 1) {
for (; b; base = 1ll * base * base % mod, b >>= 1)
if (b & 1)
ret = 1ll * ret * base % mod;
return ret;
}

void prep() {
for (ll i = 2; i * i <= x; ++i)
if (x % i == 0) {
int tmp = 0;
while (x % i == 0)
x /= i, ++tmp;
++cnt[tmp];
}
if (x > 1)
++cnt[1];
g[1] = fac[0] = fac[1] = 1;
for (int i = 2; i < N; ++i) {
fac[i] = 1ll * fac[i - 1] * i % mod;
g[i] = 1ll * (g[i - 1] + f[i - 1]) * i % mod;
f[i] = 1ll * (1ll * f[i - 1] + f[i - 1] + g[i - 1]) * i % mod * (i - 1) % mod * 499122177ll % mod;
}
}

int main() {
//freopen("in", "r", stdin);
freopen("pj.in", "r", stdin);
freopen("pj.out", "w", stdout);
x = lin(), T = in();
prep();
while (T--) {
n = in();
printf("%lld\n", 1ll * qpow(f[n] + g[n], cnt[2]) * qpow(fac[n], cnt[1]) % mod * qpow(2, 1ll * (n - 1) * (n - 1) % (mod - 1)) % mod);
}
return 0;
}


# T3、提高组

$1$ ~ $n \ (n \leq 10 ^ 7）$的排列中，确定 $a_x = y$ 后最长下降子序列不超过 $2$ 的方案数，$T \ (T \leq 10 ^ 6)$ 组询问，答案对 $10 ^ 9 + 7$ 取余。

## $Sol$：

1、一个排列一定对应它的前缀 $max$ 序列；
2、排列中没有对前缀 $max$ 序列造成影响的数也是确定的。
$QED$

$y \geq x$，那么 $y$ 一定对 $max$ 造成影响，可以考虑反证：

$y < x$，显然 $y$ 不对 $max$ 造成影响；

1、$max_i \geq i$
2、$max_i \geq max_{i - 1}$
3、$max_n = n$
$max$ 的方案数，放在平面上折线法计数就行了。

## $Source$：

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
ll lin() {
ll x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>void out(T _) {
if (_ > 9)
out(_ / 10);
putchar(_ % 10 + 48);
}
template<typename T>inline void out_ln(T _) {
out(_), putchar('\n');
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 2e7 + 5, mod = 1e9 + 7;
int n, x, y;
int fac[N], inv[N];

int qpow(int base, int b, int ret = 1) {
for (; b; b >>= 1, base = 1ll * base * base % mod)
if (b & 1)
ret = 1ll * ret * base % mod;
return ret;
}

void prep() {
fac[0] = inv[0] = 1;
for (int i = 1; i < N; ++i)
fac[i] = 1ll * fac[i - 1] * i % mod;
inv[N - 1] = qpow(fac[N - 1], mod - 2);
for (int i = N - 2; i; --i)
inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
}

inline int C(const int n, const int m) {
return n < m ? 0 : 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;
}

int main() {
//freopen("in", "r", stdin);
freopen("tg.in", "r", stdin);
freopen("tg.out", "w", stdout);
int T = in(), res = 0;
prep();
while (T--) {
n = in(), x = in(), y = in();
if (y < x)
std::swap(x, y);
res = 1ll * (C(x + y - 2, x - 1) - C(x + y - 2, x - 2)) * (C(n - x + n - y, n - x) - C(n - x + n - y, n - x + 1)) % mod;
if (res < 0)
res += mod;
out_ln(res);
}
return 0;
}

posted @ 2019-08-16 09:38  15owzLy1  阅读(45)  评论(1编辑  收藏