BZOJ3456【分治FFT】

然而会TLE.

/* I will wait for you */

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <string>
#define make(a,b) make_pair(a,b)
#define fi first
#define se second

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef map<int, int> mii;

const int maxn = 1000010;
const int maxm = 1010;
const int maxs = 26;
const int inf = 0x3f3f3f3f;
const ll P = 479 << 21 ^ 1;
const ll G = 3;
const double error = 1e-9;

inline ll read()
{
	ll x = 0, f = 1; char ch = getchar();
	while (ch > '9' || ch < '0' )
		f = (ch == '-' ? -1 : 1), ch = getchar();
	while (ch <= '9' && ch >= '0')
		x = x * 10 + ch - '0', ch = getchar();
	return f * x;
}

ll n, _x[maxn], _y[maxn], rev[maxn], w[2][maxn],
   f[maxn], I[maxn], nI[maxn], C[maxn];

ll _pow(ll a, ll b)
{
	ll ans = 1;
	for (; b; a = a * a % P, b /= 2)
		if (b & 1) ans = ans * a % P;
	return ans;
}

void init()
{
	n = read(), I[0] = nI[0] = 1;
	
	for (int i = 1; i <= n << 1; i++) {
		I[i] = I[i - 1] * i % P;
		nI[i] = _pow(I[i], P - 2);
	}

	for (int i = 1; i <= n << 1; i++)
		C[i] = _pow(2, 1ll * i * (i - 1) / 2);
}

void NTT(ll *a, int n, int f)
{
	for (int i = 0; i < n; i++) {
		rev[i] = 0;
		for (int j = i, k = 1; k < n; k <<= 1, j >>= 1)
			(rev[i] <<= 1) |= j & 1;
		if (rev[i] > i) swap(a[i], a[rev[i]]);
	}

	w[0][0] = w[1][0] = 1;
	for (int i = 1; i < n; i++) {
		w[0][i] = w[0][i - 1] * _pow(G, (P - 1) / n) % P;
		w[1][i] = _pow(w[0][i], P - 2);
	}

	for (int i = 1; i < n; i <<= 1)
	for (int j = 0, l = n / (i << 1); j < n; j += (i << 1))
	for (int k = 0, t = 0; k < i; k += 1, t += l) {
		ll x = a[j + k], y = w[f][t] * a[i + j + k] % P;
		a[j + k] = (x + y) % P, a[i + j + k] = (x - y + P) % P;
	}

	for (int i = 0; f && i < n; i++)
		a[i] = a[i] * _pow(n, P - 2) % P;
}	

void solve(int l, int r)
{
	int mid = (r + l) / 2, len = 1;

	if (l == r) {
		f[mid] = C[mid] - I[mid - 1] * f[mid] % P;
		f[mid] = (f[mid] + P) % P; return;
	}

	while (1 << len < (r - l) << 1) len += 1;

	solve(l, mid);

	for (int i = 0; i <= 1 << len; i++)
		_x[i] = _y[i] = 0;
	for (int i = l; i <= mid; i++)
		_x[i - l] = nI[i - 1] * f[i] % P;
	for (int i = l; i <= r; i++)
		_y[i - l] = C[i - l] * nI[i - l] % P;

	NTT(_x, 1 << len, 0);
	NTT(_y, 1 << len, 0);
	for (int i = 0; i <= 1 << len; i++)
		_x[i] = _x[i] * _y[i] % P;
	NTT(_x, 1 << len, 1);

	for (int i = mid + 1; i <= r; i++)
		f[i] = (f[i] + _x[i - l]) % P;	

	solve(mid + 1, r);
}

int main()
{
	init(), solve(1, n), printf("%lld\n", f[n]);	

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值