NOI模拟(5.4) CQOID2T2 九连环

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/scar_lyw/article/details/80212957

九连环

题目背景:

5.4 模拟 CQOI2018D2T2  

分析:多项式乘法FFT + 矩阵快速幂

 

首先,第一反应是觉得这个题目长的又长又奇怪,非常担心打错文件名。考虑分析一下这道题给出的性质,显然对于一个i个环的情况,我们一定需要先解下前i - 2个环,然后将第i个环放下,然后为了取下第i - 1个环,显然需要放回第i - 2,放回第i - 2显然又需要第i - 3······也就是说最后i - 2个环又要全部放回去,最后再重新把i - 1个环取下,显然放回环的最优策略和取下环的最优策略是一样的,所以最终的f[i] = f[i - 1] + 2 * f[i - 2] + 1,考场上只想到了递推式,所以感觉很GG,考场上洗了矩阵快速幂套FFT多项式乘法,复杂度是O(T * LlogL * logn)L表示答案长度,常数巨大无比,本机10100000要跑4.5秒,但是不知道为什么开了O2只要0.6秒·····对此无能为力。然后报着凉掉的心态交上去,竟然过了·····表示懵逼,可能我对数据存在误解吧·····考虑标算,我们可以发现答案的二进制是101010……然后就可以很显然的看出答案是floor((2n +1 - 1) / 3)直接求出2n + 1然后暴力就可以了·····智商被操系列·····

 

Source:

/*
    created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>
 
inline char read() {
    static const int IN_LEN = 1024 * 1024;
    static char buf[IN_LEN], *s, *t;
    if (s == t) {
        t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
        if (s == t) return -1;
    }
    return *s++;
}
 
///*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = read(), iosig = false; !isdigit(c); c = read()) {
        if (c == -1) return ;
        if (c == '-') iosig = true; 
    }
    for (x = 0; isdigit(c); c = read()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}


template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
    for (int i = 0; i <= 10; ++i) std::cout << obuf[i];
    std::cout << '\n';
	fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}
 
/*
template<class T>
inline void R(T &x) {
    static char c;
    static bool iosig;
    for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
        if (c == '-') iosig = true; 
    for (x = 0; isdigit(c); c = getchar()) 
        x = ((x << 2) + x << 1) + (c ^ '0');
    if (iosig) x = -x;
}
//*/

const int MAXN = 40000 + 10;

const double PI = acos(-1.0);

struct complex {
	double r, i;
    complex() {}
	complex(double r, double i) : r(r), i(i) {}
	inline complex operator + (const complex &x) { 
        return complex(r + x.r, i + x.i); 
    }

	inline complex operator - (const complex &x) { 
        return complex(r - x.r, i - x.i); 
    }

	inline complex operator * (const complex &x) { 
        return complex(r * x.r - i * x.i, r * x.i + i * x.r); 
    }

	inline complex conj() { 
        return complex(r, -i); 
    }
} f[MAXN << 1 | 1], h[MAXN << 1 | 1];

inline void fft(complex *a, int n, int f) {
    for (int i = 0, j = 0; i < n; ++i) {
        if (i > j) std::swap(a[i], a[j]);
        for (int k = n >> 1; (j ^= k) < k; k >>= 1) ;
    }
    
    for (int i = 1; i < n; i <<= 1) {
        complex wn = complex(cos(PI / i), sin(PI / i) * f);
        for (int j = 0; j < n; j += (i << 1)) {
            complex w = complex(1, 0);
            for (int k = 0; k < i; ++k) {
                complex &A = a[i + j + k], &B = a[j + k], t = w * A;
				A = B - t, B = B + t, w = w * wn;
            }
        }
    }

    if (f == -1) for (register int i = 0; i < n; ++i) a[i].r /= n;
}

inline void multiply(complex *a, complex *b, int k) {
	fft(a, k, 1);
	for(int i = 0, j; i < k; ++i) j = (k - 1) & (k - i), b[i] = (a[i]
        * a[i] - (a[j] * a[j]).conj()) * complex(0, -0.25);
	fft(b, k, -1);
}

struct big_int {
    int len;
    int a[MAXN];

    big_int() {}
    big_int(int x) {
        memset(a, 0, sizeof(int) * (31000));
        len = 0, a[0] = x;
    }

    inline big_int operator + (const big_int &c) const {
        big_int ans = big_int(0);
        for (int i = 0, end = std::max(len, c.len) + 5; 
            i <= end; ++i) {
            ans.a[i] += a[i] + c.a[i];
            ans.a[i + 1] += ans.a[i] / 10, ans.a[i] %= 10;
        }
        ans.len = std::max(len, c.len) + 5;
        while (ans.a[ans.len] == 0) ans.len--;
        if (ans.len == -1) ans.len = 0;
        return ans;
    }

    inline big_int operator * (const big_int &c) const {
        int n = len, m = c.len, k = 1;
        for (m += n; k <= m; k <<= 1);
        for (int i = 0; i < k; ++i) f[i].i = f[i].r = 0;
        for (int i = 0; i <= len; ++i) f[i].i = a[i];
        for (int i = 0; i <= c.len; ++i) f[i].r = c.a[i];
        multiply(f, h, k);
        big_int ans = big_int(0);
        for (int i = 0; i <= m; ++i) ans.a[i] = int(h[i].r + 0.5);
        for (int i = 0; i <= m + 5; ++i)
            ans.a[i + 1] += ans.a[i] / 10, ans.a[i] %= 10;
        ans.len = m + 5;
        while (ans.a[ans.len] == 0) ans.len--;
        if (ans.len == -1) ans.len = 0;
        return ans;
    }
} ;

struct matrix {
    big_int a[2][2];
    
    inline matrix operator * (const matrix &c) const {
        matrix temp;
        temp.a[0][0] = a[0][0] * c.a[0][0] + a[0][1] * c.a[1][0];
        temp.a[0][1] = a[0][0] * c.a[0][1] + a[0][1] * c.a[1][1];
        temp.a[1][0] = a[1][0] * c.a[0][0] + a[1][1] * c.a[1][0];
        temp.a[1][1] = a[1][0] * c.a[0][1] + a[1][1] * c.a[1][1];
        return temp;
    }

    inline matrix operator ^ (const int &x) const {
        int b = x;
        matrix a = *this, ans;
        ans.a[0][0] = ans.a[1][1] = big_int(1);
        ans.a[0][1] = ans.a[1][0] = big_int(0);
        for (; b; b >>= 1, a = a * a)
            if (b & 1) ans = ans * a;
        return ans;
    }
} move;

inline void solve(int n) {
    move.a[0][0] = big_int(4), move.a[1][0] = move.a[1][1] = big_int(1);
    move.a[0][1] = big_int(0);
    move = (move ^ ((n - 1) / 2));
    big_int ans;
    ans = move.a[0][0] + move.a[1][0];
    if (n % 2 == 0) ans = ans + ans;
    for (int i = ans.len; i >= 0; --i) std::cout << ans.a[i];
    std::cout << '\n';
}

int t, n;
int main() {
    freopen("baguenaudier.in", "r", stdin);
    freopen("baguenaudier.out", "w", stdout);
    R(t);
    while (t--) R(n), solve(n);
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页