lj竞赛图。
考虑把强联通分量缩点,大概是这样的(画图水平有限):
看那些红色标记的边,强联通分量个数=红色边的个数+1
红色边的判定条件?
设它左边的点集为S,右边的为T。
S到T的边方向一定要是S->T。
当m=0时,枚举S的大小,就可以算答案了。
Ans=∑n−1i=1Cin∗2i∗(n−i)
当m>0时,考虑用背包来解决这个问题。
对于一条路径,考虑枚举的S集它从左往右数的多少个点?
如果有i个,
i=0或i=n,系数的贡献是1。
i>0且i < n,因为 2i∗(n−i) 这条式子包含了中间的这条连接边,而连接边的方向是确定的,所以系数要是2,去消掉一个多余的1/2。
设路径点数为k,看作一个多项式,大概是 (1+2x1+2x2+…+2xk−1+xk)
其它的点的多项式是 (1+x)
用分治fft去加速这个把它们乘起来的过程,设最后的式子是A,则 Ans=∑n−1i=1Ai∗2i∗(n−i)
O(n log2 n) 居然能过,有点假。
其实上面本质是一个背包问题。
dalao yww 把多项式用生成函数乱搞,然后求exp,再回来,完全不懂,博主表示自己弱爆了~~
#include
#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define ff(i, x, y) for(int i = x; i < y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;
const int mo = 998244353;
const int N = 1e5 + 5;
int n, m, l[N], r[N], x, p;
ll a[N * 2];
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
ll w[N * 4];
int tp;
void dft(ll *a, int n) {
ff(i, 0, n) {
int p = i, q = 0;
fo(j, 1, tp) q = q * 2 + p % 2, p /= 2;
if(q > i) swap(a[q], a[i]);
}
for(int m = 2; m <= n; m <<= 1) {
int h = m / 2;
ff(i, 0, h) {
ll W = w[i * (n / m)];
for(int j = i; j < n; j += m) {
int k = j + h;
ll u = a[j], v = a[k] * W % mo;
a[j] = (u + v) % mo; a[k] = (u - v + mo) % mo;
}
}
}
}
void fft(ll *a, ll *b, int n) {
ll v = ksm(3, (mo - 1) / n); w[0] = 1;
fo(i, 1, n) w[i] = w[i - 1] * v % mo;
dft(a, n); dft(b, n); ff(i, 0, n) a[i] = a[i] * b[i] % mo;
fo(i, 0, n / 2) swap(w[i], w[n - i]);
dft(a, n); v = ksm(n, mo - 2);
ff(i, 0, n) a[i] = a[i] * v % mo;
}
ll b[N * 4], c[N * 4];
void dg(int x, int y) {
if(x == y) return;
int m = x + y >> 1;
dg(x, m); dg(m + 1, y);
int n = r[x] - l[x] + r[m + 1] - l[m + 1];
tp = 0; while(1 << ++ tp <= n);
ff(i, 0, 1 << tp) b[i] = c[i] = 0;
fo(i, l[x], r[x]) b[i - l[x]] = a[i];
fo(i, l[m + 1], r[m + 1]) c[i - l[m + 1]] = a[i];
fft(b, c, 1 << tp);
r[x] = l[x] + n;
fo(i, l[x], r[x]) a[i] = b[i - l[x]];
}
int main() {
freopen("graph.in", "r", stdin);
freopen("graph.out", "w", stdout);
scanf("%d %d", &n, &m);
r[0] = -1;
fo(i, 1, m) {
scanf("%d", &x);
l[i] = r[i - 1] + 1;
r[i] = l[i] + x;
p += x;
a[l[i]] = 1;
fo(j, l[i] + 1, r[i] - 1) a[j] = 2;
a[r[i]] = 1;
int xx = x;
fo(j, 1, xx) scanf("%d", &x);
}
fo(i, 1, n - p) ++ m, l[m] = r[m - 1] + 1, r[m] = l[m] + 1, a[l[m]] = a[r[m]] = 1;
dg(1, m);
ll ans = 0, v = ksm(2, mo - 2);
fo(i, 1, n - 1) ans = (ans + a[i] * ksm(v, (ll) i * (n - i))) % mo;
printf("%lld", (ans + 1) % mo);
}