1. 程式人生 > >[CQOI 2018]九連環

[CQOI 2018]九連環

ace sca 沒有 有環 put () ret tro ID

Description

題庫鏈接

給你一個 \(n\) 連環,遊戲規則是:

  1. 第一個(最右邊)環任何時候都可以任意裝上或卸下;
  2. 如果第 \(k\) 個環沒有被卸下,且第 \(k\) 個環右邊的所有環都被卸下,則第 \(k+1\) 個環(第 \(k\) 個環左邊相鄰的環)可以任意裝上或卸下。

現在 \(m\) 組詢問,每組詢問給你 \(n\) 連環,問你至少多少步取下所有的環。

\(1\leq n\leq 10^5,1\leq m\leq 10\)

Solution

數學書上推導很清楚了:

技術分享圖片

技術分享圖片

值得註意的是第二張圖片中的 \(n\) 為奇數的推導式中 \(\frac{2(1-2^{n+1})}{1-2^2}\)

應該是 \(\frac{1-2^{n+1}}{1-2^2}\)

有幸能指出數學書的錯誤。

然後 \(\text{FFT}\) 快速冪亂搞就好了。不開 \(-O2\)\(\text{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; }

[CQOI 2018]九連環