@Falsyta
2015-08-11T01:30:05.000000Z
字数 5384
阅读 1570
OI mxh带窝飞
给出无向图
给出长度为
有一个初始HP为
考虑原问题即为基环树子图的计数。
考虑枚举环上的点的集合
时间复杂度
# include <cstdio># include <cstring># include <iostream># include <algorithm>using namespace std;# define REP(i, n) for (int i = 1; i <= n; i ++)# define REP_0(i, n) for (int i = 0; i < n; i ++)# define FOR(i, a, b) for (int i = a; i <= b; i ++)# define Mimo(x) if (x >= P) x -= P;# define RST(a) memset (a, 0, sizeof (a))const int NR = 18, P = 998244353;int n, m, deg[NR], inv[40], a[NR][NR], h[NR][1 << 16], ps[1 << 16], bc[1 << 16];bool g[NR][NR];inline int Pow (int a, int z) {int s = 1; do {if (z & 1) s = 1ll * s * a % P; a = 1ll * a * a % P;} while (z >>= 1); return s;}inline int Inv (int x){if (x <= 30) return inv[x];if (x == P - 1) return inv[0];return Pow (x, P - 2);}int Gauss (int n){int s = 1;REP (i, n){if (!a[i][i]) FOR (j, i + 1, n) if (a[j][i]) {if (s) s = P - s; REP (k, n) swap (a[i][k], a[j][k]); break;}if (!a[i][i]) return 0;FOR (j, i + 1, n){if (!a[j][i]) continue;int t = 1ll * a[j][i] * Inv (a[i][i]) % P;REP (k, n) {a[j][k] = a[j][k] - 1ll * t * a[i][k] % P + P; Mimo (a[j][k]);}}s = 1ll * s * a[i][i] % P;}return s;}# define in(a, b) ((b) >> (a) & 1)int main (){inv[0] = Pow (P - 1, P - 2);REP (i, 30) inv[i] = Pow (i, P - 2);while (scanf ("%d%d", &n, &m) != EOF){int t1, t2;const int M = 1 << n;REP_0 (i, n) {deg[i] = 0; REP_0 (j, n) g[i][j] = 0; REP_0 (s, M) h[i][s] = 0;}REP (i, m) scanf ("%d%d", &t1, &t2), t1 --, t2 --, g[t1][t2] = g[t2][t1] = 1, deg[t1] ++, deg[t2] ++;REP_0 (i, n){ps[1 << i] = i, h[i][1 << i] = 1;REP (s, M - 1){if ((s == 1 << i) || !in (i, s) || ((s & - s) != (1 << i))) continue;FOR (j, i + 1, n - 1) if (in (j, s)) {int sa = (s ^ (1 << j)); FOR (k, i, n - 1) if (in (k, sa) && g[k][j]) {h[j][s] += h[k][sa]; Mimo (h[j][s]);}}}}int ans = 0;REP (s, M - 1){int pt = s & -s;bc[s] = bc[s ^ pt] + 1;if (bc[s] < 3) continue;pt = ps[pt]; int ts = 0;REP_0 (v, n) if (in (v, s) && g[v][pt]) {ts += h[v][s]; Mimo (ts);}ts = 1ll * ts * inv[2] % P;int c0 = 0;REP_0 (i, n){if (in (i, s)) continue;c0 ++; int c1 = 0;REP_0 (j, n) if (!in (j, s)) a[c0][++ c1] = (i == j ? deg[i] : (g[i][j] ? P - 1 : 0));}int tmp;ans = (ans + 1ll * (tmp = Gauss (n - bc[s])) * ts) % P;}printf ("%d\n", ans);}return 0;}
考虑用前缀和转成卷积的形式
可以用long double或CRT。
# include <cstdio># include <algorithm># include <cmath># define REP(i, n) for (int i = 1; i <= n; i ++)# define REP_0(i, n) for (int i = 0; i < n; i ++)# define REP_0N(i, n) for (int i = 0; i <= n; i ++)typedef long long ll;typedef long double dd;const dd PI = acosl (-1.0);const int NR = 101000;using namespace std;struct cp{dd r, i;cp () {r = i = 0;}cp (dd _r, dd _i) {r = _r, i = _i; }cp operator + (cp b) {return cp (r + b.r, i + b.i); }cp operator - (cp b) {return cp (r - b.r, i - b.i); }cp operator * (cp b) {return cp (r * b.r - i * b.i, r * b.i + i * b.r); }} a[NR << 1], b[NR << 1];ll ans[NR << 1], su[NR << 1];int n, s[NR], q0;void FFT (cp *a, int n, int ty = 1){for (int i = n >> 1, j = 1, k; j < n - 1; j ++){if (i > j) swap (a[i], a[j]);for (k = n >> 1; k <= i; k >>= 1) i ^= k;i ^= k;}for (int m = 2; m <= n; m <<= 1){int h = m >> 1;cp wm (cos (PI / h), sin (PI / h) * ty);for (int i = 0; i < n; i += m){cp w (1, 0);for (int j = i; j < i + h; j ++){cp u = a[j], v = w * a[j + h];a[j] = u + v, a[j + h] = u - v, w = w * wm;}}}if (ty == -1) REP_0 (i, n) a[i].r /= n;}int main (){REP (i, 100000) su[i] = su[i - 1] + 1ll * i * (i + 1) / 2;for (scanf ("%d", &q0); q0; q0 --){scanf ("%d", &n); int N = 1, lz = 0, ta;ans[0] = 0;REP (i, n){scanf ("%d", &ta), s[i] = s[i - 1] + ta;if (!ta) lz ++;else ans[0] += su[lz], lz = 0;}ans[0] += su[lz];for (; N <= 2 * s[n] + 20; N <<= 1) ;REP_0 (i, N) a[i] = b[i] = cp (0, 0);REP (i, n) a[s[i]].r += i;REP (i, n) b[s[n] - s[i - 1]].r += 1;FFT (a, N), FFT (b, N); REP_0 (i, N) a[i] = a[i] * b[i]; FFT (a, N, -1);REP (i, s[n]) ans[i] = (ll) (a[s[n] + i].r + 0.1);REP_0 (i, N) a[i] = b[i] = cp (0, 0);REP (i, n) a[s[i]].r += 1;REP (i, n) b[s[n] - s[i - 1]].r += i - 1;FFT (a, N), FFT (b, N); REP_0 (i, N) a[i] = a[i] * b[i]; FFT (a, N, -1);REP (i, s[n]) ans[i] -= (ll) (a[s[n] + i].r + 0.1);REP_0N (i, s[n]) printf ("%I64d\n", ans[i]);}return 0;}
首先预处理出在第
考虑令
用两个堆分别维护
算出
# include <cstdio># include <cstring># include <algorithm># include <queue>using namespace std;# define REP(i, n) for (int i = 1; i <= n; i ++)# define REP_D(i, n) for (int i = n; i >= 1; i --)priority_queue <int> Q0;priority_queue <pair <int, int> > Q1;const int NR = 501000, inf = 1 << 30;int n, m, K, a[NR], s[NR], c[NR], rib[NR], f[NR], li[NR], lim[NR];bool g[NR];int main (){while (scanf ("%d%d%d", &n, &m, &K) != EOF){bool surv = 1;REP (i, n){scanf ("%d", &a[i]), s[i] = s[i - 1] + a[i], c[i] = 0, lim[i] = max (lim[i - 1], s[i]);if (s[i] >= m + (i - 1) * K) surv = 0;}if (!surv) {puts ("Poor Hero!"); continue;}s[n + 1] = s[n], c[n + 1] = 0;int ri = 0;REP (i, n){while (ri < n && m + i * K > s[ri + 1]) ri ++;rib[i] = ri;}int ans = -1;REP (i, n){f[i] = (m > lim[i] ? inf : 0);while (!Q0.empty ()){int j = -Q0.top ();if (i > rib[j]) {Q0.pop (); continue;}if (i - j > f[j]) {Q0.pop (); Q1.push (make_pair (f[j], j)); continue;}f[i] = max (f[i], i - j); break;}while (!Q1.empty ()){int j = Q1.top ().second;if (i > rib[j]) {Q1.pop (); continue;}f[i] = max (f[i], f[j]); break;}if (i * K + m > lim[n]) ans = max (ans, f[i]);Q0.push (-i);}if (ans == inf) {puts ("Poor JRY!"); continue;}REP_D (i, n){if (i * K + m > lim[n]) {g[i] = 1, c[i] = c[i + 1] + 1; continue;}g[i] = 0, c[i] = c[i + 1];int l = i + ans, r = rib[i];if (l > r || c[r] == c[l + 1]) continue;g[i] = 1, c[i] ++;}int len = 0;REP (i, n)if (g[i]){li[++ len] = i;if (i * K + m > lim[n]) break;i += ans - 1;}printf ("%d\n%d\n", ans, len);REP (i, len) printf ("%d ", li[i]); puts ("");while (!Q0.empty ()) Q0.pop ();while (!Q1.empty ()) Q1.pop ();}return 0;}