• [CQOI 2018]九连环


    Description

    题库链接

    给你一个 (n) 连环,游戏规则是:

    1. 第一个(最右边)环任何时候都可以任意装上或卸下;
    2. 如果第 (k) 个环没有被卸下,且第 (k) 个环右边的所有环都被卸下,则第 (k+1) 个环(第 (k) 个环左边相邻的环)可以任意装上或卸下。

    现在 (m) 组询问,每组询问给你 (n) 连环,问你至少多少步取下所有的环。

    (1leq nleq 10^5,1leq mleq 10)

    Solution

    数学书上推导很清楚了:

    值得注意的是第二张图片中的 (n) 为奇数的推导式中 (frac{2(1-2^{n+1})}{1-2^2}) 应该是 (frac{1-2^{n+1}}{1-2^2})

    有幸能指出数学书的错误。

    然后 ( ext{FFT}) 快速幂乱搞就好了。不开 (-O2)( ext{FFT}) 不就是在玩火吗???

    Code

    这个瓜皮代码常数过大在 b 站上过不了。

    #include <bits/stdc++.h>
    #define dob complex<double>
    using namespace std;
    const int N = (100000<<2)+5;
    const double pi = acos(-1.);
    
    int n, nn, m, len, L, R[N], A[N];
    dob a[N], b[N];
    
    void FFT(dob *A, int o) {
        for (int i = 0; i < len; i++) if (i < R[i]) swap(A[i], A[R[i]]);
        for (int i = 1; i < len; i <<= 1) {
            dob wn(cos(pi/i), sin(pi*o/i)), x, y;
            for (int j = 0; j < len; j += (i<<1)) {
                dob w(1, 0);
                for (int k = 0; k < i; k++, w = w*wn) {
                    x = A[j+k], y = w*A[i+j+k];
                    A[j+k] = x+y, A[i+j+k] = x-y;
                }
            }
        }
    }
    void work() {
        scanf("%d", &n); nn = n; ++n; m = log(2)*n+5;
        for (L = 0, len = 1; len <= m; len <<= 1) ++L;
        for (int i = 0; i < len; i++) a[i] = b[i] = 0;
        for (int i = 0; i < len; i++) R[i] = (R[i>>1]>>1)|((i&1)<<(L-1));
        a[0] = 1, b[0] = 2;
        while (n) {
            FFT(a, 1), FFT(b, 1);
            if (n&1) for (int i = 0; i <= len; i++) a[i] = a[i]*b[i];
            for (int i = 0; i <= len; i++) b[i] = b[i]*b[i]; n >>= 1;
            FFT(a, -1); FFT(b, -1);
            for (int i = 0; i < len; i++) A[i] = a[i].real()/len+0.5;
            int loc = 0; while (A[loc] && loc < len) A[loc+1] += A[loc]/10, A[loc] %= 10, ++loc;
            for (int i = 0; i < len; i++) a[i] = A[i];
            for (int i = 0; i < len; i++) A[i] = b[i].real()/len+0.5;
            loc = 0; while (A[loc] && loc < len) A[loc+1] += A[loc]/10, A[loc] %= 10, ++loc;
            for (int i = 0; i < len; i++) b[i] = A[i];
        }
        for (int i = 0; i < len; i++) A[i] = a[i].real();
        A[0] -= 1+(!(nn&1));
        for (int i = len-1, flag = 0, sum = 0; i >= 0; i--) {
            sum = sum*10+A[i]; if (sum/3) flag = 1;
            if (flag) printf("%d", sum/3), sum %= 3;
        }
        puts("");
    }
    int main() {int t; cin >> t; while (t--) work(); return 0; }
  • 相关阅读:
    Yii框架中ActiveRecord使用Relations
    MySQL外键约束On Delete、On Update各取值的含义
    30种mysql优化sql语句查询的方法
    PHP数组常用函数
    yii CListView中使用CArrayDataProvider自定义数组作为数据
    java日常统计
    软件工程概论———登录界面的设计
    Java课堂疑问解答与思考5
    Java课堂疑问解答与思考4
    字符串加密
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8989286.html
Copyright © 2020-2023  润新知