3-idiots
阿新 • • 發佈:2018-10-06
練習 math con while double class sum pan 容斥
個人理解
第一道\(FFT\)練習題,盡管開始會用模板,但還是心存疑惑
- \(IDFT\)的過程還是不會證
- 自底向上的叠代,取值過程依然模糊
- 線性卷積和循環卷積為什麽在\(L > (n + m - 1)\)時相等
- ········
當你學會了\(FFT\),那麽這道題剩下的就是一丟丟容斥(枚舉不合法的情況)kuangbin聚聚的博客講的很清楚,就是自己寫的時候要仔細!
long long cnt = 0; for (int i = 0; i < n; ++i) { cnt += (sum[len - 1] - sum[a[i]]); // 0, 1, ···,len - 1 cnt -= (long long)i * (n - i - 1); // 一個取大一個取小 cnt -= (n - 1); // 一個取本身,一個取其它數 cnt -= (long long)(n - i - 1) * (n - i - 2) / 2; }
代碼
struct Complex { double real, image; Complex() {} Complex(double real, double image) : real(real), image(image) {} Complex operator + (const Complex &a) const { return Complex(real + a.real, image + a.image); } Complex operator - (const Complex &a) const { return Complex(real - a.real, image - a.image); } Complex operator * (const Complex &a) const { return Complex(real * a.real - image * a.image, image * a.real + real * a.image); } }; int rev(int id, int len) { int pos = 0; for (int i = 0; (1 << i) < len; ++i) { pos <<= 1; if (id & (1 << i)) pos |= 1; } return pos; } Complex A[500005]; void FFT(Complex *a, int len, int DFT) { rep(i, 0, len) A[rev(i, len)] = a[i]; for (int s = 1; (1 << s) <= len; ++s) { int m = (1 << s); Complex wm = Complex(cos(DFT * 2 * PI / m), sin(DFT * 2 * PI / m)); for (int i = 0; i < len; i += m) { Complex w = Complex(1, 0); for (int j = 0; j < (m >> 1); ++j) { Complex t = A[i + j]; Complex u = w * A[i + j + (m >> 1)]; A[i + j] = t + u; A[i + j + (m >> 1)] = t - u; w = w * wm; } } } if (DFT == -1) rep(i, 0, len) A[i].real /= len, A[i].image /= len; rep(i, 0, len) a[i] = A[i]; } const int N = 500005; int n; int cnt[N], b[N]; Complex a[N]; LL sum[N], num[N]; int main() { BEGIN() { mem(cnt, 0); mem(num, 0); sc(n); int ma = 0; rep(i, 0, n) { sc(b[i]); int x = b[i]; cnt[x]++; num[x + x]--; ma = max(ma, x); } int sa = 0; while((1 << sa) < (ma + 1)) sa++; int m = 1 << (sa + 1); rep(i, 0, m) a[i] = Complex(cnt[i], 0); FFT(a, m, 1); rep(i, 0, m) a[i] = a[i] * a[i]; FFT(a, m, -1); rep(i, 0, m) num[i] += (LL)(a[i].real + 0.5), num[i] /= 2; rep(i, 1, m) sum[i] = sum[i - 1] + num[i]; sort(b, b + n); LL cnt = 0; rep(i, 0, n) { cnt += (sum[m - 1] - sum[b[i]]); cnt -= (LL)(n - 1 - i) * i; cnt -= (n - 1); cnt -= (LL)(n - 1 - i) * (n - i - 2) / 2; } LL tot = (LL)n * (n - 1) * (n - 2) / 6; printf("%.7f\n", (double)cnt / tot); } return 0; }
3-idiots