「LOJ2462」「2018 集訓隊互測 Day 1」完美的集合-DP
阿新 • • 發佈:2018-12-31
Description
Solution
首先對於每一種選取 個集合的方案,合法的測試點一定是個聯通塊。
所以可以容斥求出方案數,即 可行的減去 與 都可行的。
剩下的是一個組合數取模的問題,即求
設多項式 ,所求為 的常數項。
設 為 不超過 的最大整數,求 後剩下的暴力乘上去。 ,注意當 展開到第 項後貢獻為 ,所以只保留前 項即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
typedef pair<lint, lint> pll;
const lint mod = 11920928955078125, phi = mod / 5 * 4;
const int maxn = 65, maxm = 10005, maxd = 25;
int n, m, k, w[maxn], v[maxn];
lint Max, lim, ans;
int dis[maxn][maxn], fa[maxn];
inline lint gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
lint sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
inline lint inc(lint a, lint b) {return a + b >= mod ? a + b - mod : a + b;}
inline lint mul(lint a, lint b) {return (__int128)a * b % mod;}
inline lint fpow(lint x, lint k)
{
lint res = 1;
while (k) {
if (k & 1) res = mul(res, x);
x = mul(x, x); k >>= 1;
}
return res;
}
inline lint inv(lint x) {return fpow(x, phi - 1);}
namespace Binom
{
lint C[maxd][maxd], pw[maxd];
struct poly
{
lint a[maxd];
poly() {memset(a, 0, sizeof(a));}
poly(lint d) {
memset(a, 0, sizeof(a));
a[1] = 1;
a[0] = d;
}
friend inline poly operator * (const poly &a, const poly &b) {
poly c;
for (int i = 0; i <= 23; ++i)
if (b.a[i])
for (int j = 0; i + j <= 23; ++j)
c.a[i + j] = inc(c.a[i + j], mul(a.a[j], b.a[i]));
return c;
}
void extend(lint k)
{
pw[0] = 1;
for (int i = 1; i <= 23; ++i) pw[i] = mul(pw[i - 1], k);
for (int i = 0; i <= 23; ++i) {
lint res = 0;
for (int j = i; j <= 23; ++j) res = inc(res, mul(a[j], mul(C[j][i], pw[j - i])));
a[i] = res;
}
}
} pre[10005];
void prepare()
{
C[0][0] = 1;
for (int i = 1; i <= 23; ++i) {
C[i][0] = 1;
for (int j = 1; j <= 23; ++j)
C[i][j] = inc(C[i - 1][j - 1], C[i - 1][j]);
}
pre[0].a[0] = 1;
for (int i = 1; i <= 10000; ++i)
if (i % 5) pre[i] = pre[i - 1] * poly(i);
else pre[i] = pre[i - 1];
}
inline poly getpoly(lint n)
{
if (n <= 10000) return pre[n];
lint k = n / 10 * 10;
poly t1 = getpoly(k >> 1), t2 = t1;
t2.extend(k >> 1);
t2 = t1 * t2;
for (lint i = k + 1; i <= n; ++i)
if (i % 5) t2 = t2 * poly(i);
return t2;
}
inline pll calc(lint n)
{
poly t = getpoly(n);
lint res = n / 5;
if (res > 0) {
pll t2 = calc(n / 5);
t.a[0] = mul(t.a[0], t2.first);
res = inc(res, t2.second);
}
return make_pair(t.a[0], res);
}
inline lint binom(lint n)
{
if (n < k) return 0;
pll t1 = calc(n), t2 = calc(n - k), t3 = calc(k);
t1.second -= (t2.second + t3.second);
if (t1.second >= 23) return 0;
t1.first = mul(t1.first, mul(fpow(5, t1.second), inv(mul(t2.first, t3.first))));
return t1.first;
}
}
namespace tree
{
struct edge
{
int to, next, w;
} e[maxn * 2];
int h[maxn], tot;
int valid[maxn], id[maxn], siz[maxn], cnt;
lint f[maxn][maxm], g[maxn][maxm];
inline void add(int u, int v, int w)
{
e[++tot] = (edge