首页 > 其他分享 >【题解】[GDKOI2021] 空中恋爱论

【题解】[GDKOI2021] 空中恋爱论

时间:2023-03-02 17:46:30浏览次数:41  
标签:GDKOI2021 int 题解 FFT rev leq 恋爱 maxn include

一场比赛,一个学长,一段故事,一场大梦。

折戟沉沙,壮志未酬。

思路

cdq 分治 + FFT。

首先意识到对和满足要求的区间计数,可以先求前缀和,再转化成前缀和的端点对计数。

令 \(A_n = \sum\limits_{i = 1}^n a_i, B_n = \sum\limits_{i = 1}^n b_i\).

那么对于一个点对 \(i, j (i \leq j)\),如果 \(B_j - B_i > 0\),就说明 \((i, j]\) 是合法的区间。

现在的问题转化成统计 \(B\) 中的每一个点对。

这个问题看起来没有其他做法,考虑分治。

假设当前区间为 \([l, r]\). 我们需要统计的点对满足 \(0 \leq l \leq i \leq \lfloor \frac{l + r}{2} \rfloor < j \leq r \leq n\),并且 \(B_j - B_i > 0\)。在此基础上,它会对 \(A_j - A_i\) 的位置贡献 \(1\).

那么先把数组按照 \(B\) 排序,保证分治时右半段区间的 \(B\) 之和大于等于做半段。然后把 \([l, mid]\) 中的点值设为 \(-A_i\),\((mid, r]\) 中的点值设为 \(A_j\). 只需要做一个无标号计数就行。随便 FFT 或者 NTT 带走。

考虑到每次都做 FFT 会浪费很多时间,考虑类似根号分治,当区间长度大于阈值时才 FFT。

阈值取 \(\sqrt{n \log n}\) 最优,时间复杂度 \(O(n \sqrt{n \log n})\).

代码

// FFT 板子掉精,我觉得该反思人品了
#include <cstdio>
#include <cmath>
#include <complex>
#include <iostream>
#include <algorithm>
using namespace std;
 
#define fi first
#define se second
 
typedef long long ll;
typedef double db;
 
const int maxn = 1e6 + 5;
const ll inf = 1e18;
const db PI = acos(-1);
 
int n;
int rev[maxn];
ll ans[maxn];
pair<ll, ll> a[maxn];
complex<double> F[maxn], G[maxn];
 
void calc_rev(int k) { for (int i = 0; i < k; i++) rev[i] = (rev[i >> 1] >> 1 | (i & 1 ? k >> 1 : 0)); }
 
// void FFT(complex<double> *A, int n)
// {
//     for (int i = 1; i < n; i++)
//         if (rev[i] > i) swap(A[i], A[rev[i]]);
//     for (int len = 2, m = 1; len <= n; m = len, len <<= 1)
//     {
//         complex<double> W(cos(PI / m), sin(PI / m)), w(1.0, 0.0);
//         for (int l = 0, r = len - 1; r <= n; l += len, r += len)
//         {
//             auto w0 = w;
//             for (int p = l; p < l + m; p++)
//             {
//                 auto x = A[p] + w0 * A[p + m], y = A[p] - w0 * A[p + m];
//                 A[p] = x, A[p + m] = y;
//                 w0 *= W;
//             }
//         }
//     }
// }
 
void FFT(complex<double>* c, int n){
    calc_rev(n);
    for (int i = 0; i < n; i++) if (i < rev[i]) swap(c[i], c[rev[i]]);
    for (int i = 1;i < n; i <<= 1)
    {
        complex<double> omn(cos(PI / i), sin(PI / i));
        for (int j = 0; j < n; j += (i << 1))
        {
            complex<double> om(1, 0);
            for (int k = 0; k < i; k++, om = om * omn)
            {
                complex<double> x = c[j + k], y = c[j + k + i] * om;
                c[j + k] = x + y, c[j + k + i] = x - y;
            }
        }
    }
}
 
void IFFT(complex<double> *A, int n)
{
    FFT(A, n), reverse(A + 1, A + n);
    for (int i = 0; i < n; i++) A[i] /= n;
}
 
void cdq(int l, int r)
{
    if (l >= r) return;
    int mid = (l + r) >> 1;
    ll lmn = inf, lmx = -inf, rmn = inf, rmx = -inf;
    cdq(l, mid), cdq(mid + 1, r);
    if (r - l <= 1e4)
    {
        for (int i = l; i <= mid; i++)
            for (int j = mid + 1; j <= r; j++)
                ans[a[j].se - a[i].se + n]++;
        return;
    }
    for (int i = l; i <= mid; i++) lmn = min(lmn, a[i].se), lmx = max(lmx, a[i].se);
    for (int i = mid + 1; i <= r; i++) rmn = min(rmn, a[i].se), rmx = max(rmx, a[i].se);
    int k = 1;
    while (k <= lmx - lmn + rmx - rmn) k <<= 1;
    for (int i = 0; i <= k; i++) F[i] = (0, 0);
    for (int i = l; i <= mid; i++)
    {
        double tmp = F[lmx - a[i].se].real() + 1.0;
        F[lmx - a[i].se].real(tmp);
    }
    for (int i = mid + 1; i <= r; i++)
    {
        double tmp = F[a[i].se - rmn].imag() + 1.0;
        F[a[i].se - rmn].imag(tmp);
    }
    FFT(F, k);
    for (int i = 0; i < k; i++) F[i] *= F[i];
    IFFT(F, k);
    for (int i = 0; i <= lmx - lmn + rmx - rmn; i++) ans[i + rmn - lmx + n] += (int)(F[i].imag() / 2.0 + 0.5);
}
 
signed main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i].se), a[i].se += a[i - 1].se;
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i].fi), a[i].fi += a[i - 1].fi;
    sort(a, a + n + 1);
    cdq(0, n);
    for (int i = 0; i <= (n << 1); i++) printf("%lld ", ans[i]);
    return 0;
}

标签:GDKOI2021,int,题解,FFT,rev,leq,恋爱,maxn,include
From: https://www.cnblogs.com/lingspace/p/xsy3885.html

相关文章

  • leetcode 2564. 子字符串异或查询[题解]
    链接:子字符串异或查询思路:题目说\(val\oplusfirst=second\)可得\(val=second\oplusfirst\)题目变成从\(0-1\)串中找到最先出现的\(val\)的二进制表示,注意是\(10^......
  • leetcode2565. 最少得分子序列[题解]
    最少得分子序列给你两个字符串s和t。你可以从字符串t中删除任意数目的字符。如果没有从字符串t中删除字符,那么得分为0,否则:令left为删除字符中的最小下标。......
  • 洛谷P4051 [JSOI2007]字符加密 题解 后缀数组sa的应用
    题目链接:https://www.luogu.com.cn/problem/P4051题目大意:给定一个长度为\(n\)的字符串\(s\),每次将\(s\)的首字符取出放到末尾……这样能得到\(n\)个字符串。将......
  • iframe sanbox 造成附件下载问题解决
    问题场景,iframe通过src加载三方website,同时三方website调用api生成web页面,页面中会包含click链接(打开新页面)之后会包含文件下载参考图如下  问题对于通过a......
  • VUE前端请求跨域问题解决
    解决方法:vue.config.js文件配置:module.exports={devServer:{open:true,host:'192.168.1.193',port:8080,https:fals......
  • Failed to run MSBuild command 错误问题解决
    场景:提示:这里简述项目相关背景:CMake报错CMakeERRORFailedtorunMSBuildcommand:MSBuild.exe。如下图所示: 问题描述提示:这里描述项目中遇到的问题:①cmake报错......
  • LOJ 3276 JOISC 2020 Day2 遗迹 题解 (计数DP)
    LOJ链接UOJ链接观察一下n次地震的过程,发现最后会有n个石柱高度为0,\(1,2\cdotsn\)高度的石柱各有一个。假设现在已经确定了一种初始高度状态,我们来看看最后哪些石柱高度......
  • P8631 [蓝桥杯 2015 国 AC] 切开字符串 题解
    P8631[蓝桥杯2015国AC]切开字符串题解前言看到这题没有人写题解,就打算写一篇。这也是蒟蒻的第一篇题解。前置知识\(manacher\),\(SA\)。如果不会可以转至mana......
  • ABC275D-Yet-Another-Recursive-Function题解
    题目传送门题意:定义一个\(\mathbb{N}\to\mathbb{N}\)的函数\(f(x)=\begin{cases}1&x=0\\f(\lfloor\frac{x}{2}\rfloor)+f(\lfloor\frac{x}{3}\rfloor)&\text{otherwis......
  • CF71D-Solitaire题解
    题目传送门题意:一副扑克牌由54张牌组成,包括52张基本牌和两张“王”。在本题中每张牌用两个字符表示:对于基本牌,第一个字符为点数,有'2''3''4''5''6''7''8''9......