记录编号 371946 评测结果 AAAAAAAAAA
题目名称 [BZOJ 3456] 城市规划 最终得分 100
用户昵称 GravatarFoolMike 是否通过 通过
代码语言 C++ 运行时间 3.243 s
提交时间 2017-02-17 13:38:21 内存使用 9.29 MiB
显示代码纯文本
#include <cstdio>
#include <algorithm>
 
using std::swap;
using std::fill;
using std::copy;
using std::reverse;
using std::reverse_copy;
 
typedef int value_t;
typedef long long calc_t;
const int MaxN = 1 << 18;
const value_t mod_base = 479, mod_exp = 21;
const value_t mod_v = (mod_base << mod_exp) + 1;
const value_t primitive_root = 3;
int epsilon_num;
value_t eps[MaxN], inv_eps[MaxN];
 
value_t dec(value_t x, value_t v) { x -= v; return x < 0 ? x + mod_v : x; }
value_t inc(value_t x, value_t v) { x += v; return x >= mod_v ? x - mod_v : x; }
value_t pow(value_t x, value_t p)
{
    value_t v = 1;
    for(; p; p >>= 1, x = (calc_t)x * x % mod_v)
        if(p & 1) v = (calc_t)x * v % mod_v;
    return v;
}
 
void init_eps(int num)
{
    epsilon_num = num;
    value_t base = pow(primitive_root, (mod_v - 1) / num);
    value_t inv_base = pow(base, mod_v - 2);
    eps[0] = inv_eps[0] = 1;
    for(int i = 1; i != num; ++i)
    {
        eps[i] = (calc_t)eps[i - 1] * base % mod_v;
        inv_eps[i] = (calc_t)inv_eps[i - 1] * inv_base % mod_v;
    }
}
 
void transform(int n, value_t *x, value_t *w = eps)
{
    for(int i = 0, j = 0; i != n; ++i)
    {
        if(i > j) swap(x[i], x[j]);
        for(int l = n >> 1; (j ^= l) < l; l >>= 1);
    }
 
    for(int i = 2; i <= n; i <<= 1)
    {
        int m = i >> 1, t = epsilon_num / i;
        for(int j = 0; j < n; j += i)
        {
            for(int p = 0, q = 0; p != m; ++p, q += t)
            {
                value_t z = (calc_t)x[j + m + p] * w[q] % mod_v;
                x[j + m + p] = dec(x[j + p], z);
                x[j + p] = inc(x[j + p], z);
            }
        }
    }
}
 
void inverse_transform(int n, value_t *x)
{
    transform(n, x, inv_eps);
    value_t inv = pow(n, mod_v - 2);
    for(int i = 0; i != n; ++i)
        x[i] = (calc_t)x[i] * inv % mod_v;
}
 
struct poly_t
{
    int deg;
    value_t x[MaxN];
    poly_t() : deg(0) { x[0] = 0; }
};
 
void polynomial_inverse(int n, const poly_t& A, poly_t& B)
{
    if(n == 1)
    {
        B.deg = 1;
        B.x[0] = pow(A.x[0], mod_v - 2);
        return;
    }
 
    static value_t X[MaxN];
    polynomial_inverse((n + 1) >> 1, A, B);
 
    int p = 1;
    for(; p < n << 1; p <<= 1);
    copy(A.x, A.x + n, X);
    fill(X + n, X + p, 0);
    transform(p, X);
 
    fill(B.x + B.deg, B.x + p, 0);
    transform(p, B.x);
 
    for(int i = 0; i != p; ++i)
        B.x[i] = (calc_t)B.x[i] * dec(2, (calc_t)X[i] * B.x[i] % mod_v) % mod_v;
    inverse_transform(p, B.x);
    B.deg = n;
}
 
poly_t A, B, C;
value_t inv[MaxN], inv_fac[MaxN], choose[MaxN];
 
int main()
{
	freopen("bzoj_3456.in","r",stdin);
	freopen("bzoj_3456.out","w",stdout);
    int n;
    std::scanf("%d", &n);
    int p = 1;
    for(; p < (n + 1) << 1; p <<= 1);
    init_eps(p);
 
    inv[1] = inv_fac[0] = 1;
    for(int i = 1; i <= n; ++i)
    {
        if(i != 1) inv[i] = -mod_v / i * (calc_t)inv[mod_v % i] % mod_v;
        if(inv[i] < 0) inv[i] += mod_v;
        inv_fac[i] = (calc_t)inv_fac[i - 1] * inv[i] % mod_v;
    }
 
    choose[0] = choose[1] = 1;
    for(int i = 2; i <= n; ++i)
        choose[i] = pow(2, (calc_t)i * (i - 1) / 2 % (mod_v - 1));
 
    A.deg = B.deg = n + 1;
    for(int i = 0; i <= n; ++i)
        A.x[i] = (calc_t)choose[i] * inv_fac[i] % mod_v;
    for(int i = 1; i <= n; ++i)
        B.x[i] = (calc_t)choose[i] * inv_fac[i - 1] % mod_v;
    polynomial_inverse(n + 1, A, C);
    fill(C.x + C.deg, C.x + p, 0);
    transform(p, C.x);
    transform(p, B.x);
    for(int i = 0; i <= p; ++i)
        C.x[i] = (calc_t)C.x[i] * B.x[i] % mod_v;
    inverse_transform(p, C.x);
    value_t ans = (calc_t)C.x[n] * pow(inv_fac[n - 1], mod_v - 2) % mod_v;
    if(ans < 0) ans += mod_v;
    std::printf("%d\n", ans);
    return 0;
}