@Falsyta
2015-08-11T01:30:05.000000Z
字数 5384
阅读 1430
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;
}