Loading [MathJax]/jax/output/CommonHTML/fonts/TeX/AMS-Regular.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >BZOJ3509: [CodeChef] COUNTARI(生成函数 分块)

BZOJ3509: [CodeChef] COUNTARI(生成函数 分块)

作者头像
attack
修改于 2019-03-19 09:08:17
修改于 2019-03-19 09:08:17
61200
代码可运行
举报
运行总次数:0
代码可运行

题意

链接

Sol

这都能分块。。。。

首先移一下项,变为统计多少i < j < k,满足2a[j]=a[i]+a[k]

发现a[i]30000,那么有一种暴力思路是枚举j,对于之前出现过的数构造一个生成函数,对于之后出现过的数构造一个生成函数,求一下第2a[j]项的值。复杂度O(nVlogV)

每次枚举j暴力卷积显然太zz了,我们可以分一下块,对于每一块之前之后的数分别构造生成函数暴力卷积算,对于块内的直接暴力(这里的暴力不只是统计块内的(i, j, k),还要考虑j, k在块内i在块外,以及i, j在块内,k在块外的情况,但都是可以暴力的)

如果分成B块的话,复杂度是NBVlogV+B2,假设n与V同阶的话,B大概取nlogn是最优的。此时复杂度为O(NNlogn)

下面的代码在原BZOJ上可能会T

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<bits/stdc++.h> 
#define Pair pair<int, int>
#define MP(x, y) make_pair(x, y)
#define fi first
#define se second
#define LL long long 
#define ull unsigned long long 
#define Fin(x) {freopen(#x".in","r",stdin);}
#define Fout(x) {freopen(#x".out","w",stdout);}
using namespace std;
const int MAXN = 1e6 + 10, INF = 1e9 + 1;
const double eps = 1e-9, pi = acos(-1);
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
namespace Poly {
    int rev[MAXN], GPow[MAXN], A[MAXN], B[MAXN], C[MAXN], lim, INV2;
    const int G = 3, mod = 1004535809, mod2 = 1004535808;
    template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
    template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
    template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
    template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
    template <typename A, typename B> inline bool chmax(A &x, B y) {return x < y ? x = y, 1 : 0;}
    template <typename A, typename B> inline bool chmin(A &x, B y) {return x > y ? x = y, 1 : 0;}
    int fp(int a, int p, int P = mod) {
        int base = 1;
        for(; p > 0; p >>= 1, a = 1ll * a * a % P) if(p & 1) base = 1ll * base *  a % P;
        return base;
    }
    int inv(int x) {
        return fp(x, mod - 2);
    }
    int GetLen(int x) {
        int lim = 1;
        while(lim < x) lim <<= 1;
        return lim;
    }
    void Init(/*int P,*/ int Lim) {
        INV2 = fp(2, mod - 2);
        for(int i = 1; i <= Lim; i++) GPow[i] = fp(G, (mod - 1) / i);
    }
    void NTT(int *A, int lim, int opt) {
        int len = 0; for(int N = 1; N < lim; N <<= 1) ++len; 
        for(int i = 1; i <= lim; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (len - 1));
        for(int i = 0; i <= lim; i++) if(i < rev[i]) swap(A[i], A[rev[i]]);
        for(int mid = 1; mid < lim; mid <<= 1) {
            int Wn = GPow[mid << 1];
            for(int i = 0; i < lim; i += (mid << 1)) {
                for(int j = 0, w = 1; j < mid; j++, w = mul(w, Wn)) {
                    int x = A[i + j], y = mul(w, A[i + j + mid]);
                    A[i + j] = add(x, y), A[i + j + mid] = add(x, -y);
                }
            }
        }
        if(opt == -1) {
            reverse(A + 1, A + lim);
            int Inv = fp(lim, mod - 2);
            for(int i = 0; i <= lim; i++) mul2(A[i], Inv);
        }
    }
    void Mul(int *a, int *b, int N, int M) {
        memset(A, 0, sizeof(A)); memset(B, 0, sizeof(B));
        int lim = 1, len = 0; 
        while(lim <= N + M) len++, lim <<= 1;
        for(int i = 0; i <= N; i++) A[i] = a[i]; 
        for(int i = 0; i <= M; i++) B[i] = b[i];
        NTT(A, lim, 1); NTT(B, lim, 1);
        for(int i = 0; i <= lim; i++) B[i] = mul(B[i], A[i]);
        NTT(B, lim, -1);
        for(int i = 0; i <= N + M; i++) b[i] = B[i];
        memset(A, 0, sizeof(A)); memset(B, 0, sizeof(B));
    }
};
using namespace Poly; 
int N, a[MAXN], mx, block, ll[MAXN], rr[MAXN], belong[MAXN], mxblock, num[MAXN];
LL Solve1(int l, int r) {
    for(int i = 1; i < l; i++) num[a[i]]++; 
    LL ret = 0;
    for(int j = l; j <= r; j++) 
        for(int k = j + 1; k <= r; k++) 
            if(2 * a[j] - a[k] >= 0) ret += num[2 * a[j] - a[k]];
    for(int i = 1; i < l; i++) num[a[i]]--;

    for(int i = N; i > r; i--) num[a[i]]++;
    for(int j = r; j >= l; j--) 
        for(int k = j - 1; k >= l; k--) 
            if(2 * a[j] - a[k] >= 0) ret += num[2 * a[j] - a[k]];
    for(int i = N; i > r; i--) num[a[i]]--;
    
    for(int j = l; j <= r; j++) {
        for(int i = j - 1; i >= l; i--) num[a[i]]++;
        for(int k = j + 1; k <= r; k++) 
            if(2 * a[j] - a[k] >= 0) ret += num[2 * a[j] - a[k]];
        for(int i = j - 1; i >= l; i--) num[a[i]]--;
    }
    return ret;
}
int ta[MAXN], tb[MAXN], Lim;
LL Solve2(int l, int r) {
    memset(ta, 0, sizeof(ta));
    memset(tb, 0, sizeof(tb));
    for(int i = l - 1; i >= 1; i--) ta[a[i]]++;
    for(int i = r + 1; i <= N; i++) tb[a[i]]++;
    Mul(ta, tb, mx, mx); LL ret = 0;
    for(int i = l; i <= r; i++) ret += tb[2 * a[i]];
    return ret;
}
signed main() {
    //freopen("a.in", "r", stdin);  
    N = read(); block = sqrt(8 *  N * log2(N)); 
    memset(ll, 0x3f, sizeof(ll));
    for(int i = 1; i <= N; i++) {
        belong[i] = (i - 1) / block + 1; chmax(mxblock, belong[i]);
        chmin(ll[belong[i]], i);
        chmax(rr[belong[i]], i);
        a[i] = read(), chmax(mx, a[i]);
    }
    Lim = GetLen(mx); Init(4 * Lim);
    LL ans = 0;
    for(int i = 1; i <= mxblock; i++) {
        ans += Solve1(ll[i], rr[i]);
        ans += Solve2(ll[i], rr[i]);
    }
    cout << ans;
    return 0;
}
/*
7
7 0 4 7 0 8 8 
*/
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-03-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
HDU4609 3-idiots(生成函数)
但是如果直接算合法的方案的话会出现一点问题。我们在算的时候维护了一个后缀和表示乘起来大于等于这个数的方案。我们要求的方案需要满足i < j < k,但是这样计算可能会出现不合法的情况。
attack
2019/03/19
7020
loj#6074. 「2017 山东一轮集训 Day6」子序列(矩阵乘法 dp)
然后发现可以用矩阵优化,可以分别求出前缀积和逆矩阵的前缀积(这题的逆矩阵炒鸡好求)
attack
2019/04/01
5290
洛谷P3199 [HNOI2009]最小圈(01分数规划)
题意 题目链接 Sol 暴力01分数规划可过 标算应该是这个 #include<bits/stdc++.h> #define Pair pair<int, double> #define MP(x, y) make_pair(x, y) #define fi first #define se second //#define int long long #define LL long long #define Fin(x) {freopen(#x".in","r",stdin);} #define F
attack
2019/03/15
4000
loj#6032. 「雅礼集训 2017 Day2」水箱(并查集 贪心 扫描线)
一个连通块的内状态使用两个变量即可维护\(ans\)表示联通块内的最大答案,\(f\)表示联通块内\(k=1\)的数量
attack
2019/03/20
4510
洛谷P4462 [CQOI2018]异或序列(莫队)
题意 题目链接 Sol 一开始以为K每次都是给出的想了半天不会做。 然而发现读错题了维护个前缀异或和然后直接莫队搞就行,。 #include<bits/stdc++.h> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #define fi first #define se second //#define int long long #define LL long long #define Fin(x) {freopen(#x
attack
2019/03/15
3270
洛谷P2868 [USACO07DEC]观光奶牛Sightseeing Cows(01分数规划)
设\(a_i\)为点权,\(b_i\)为边权,我们要最大化\(\sum \frac{a_i}{b_i}\)。可以二分一个答案\(k\),我们需要检查\(\sum \frac{a_i}{b_i} \geqslant k\)是否合法,移向之后变为\(\sum_{a_i} - k\sum_{b_i} \geqslant 0\)。把\(k * b_i\)加在出发点的点权上检查一下有没有负环就行了
attack
2019/03/15
3630
洛谷P4561 [JXOI2018]排序问题(二分 期望)
一次排好的概率是个数数题,他等于一次排好的方案除以总方案,也就是\(\frac{\prod cnt_{a_i}!}{(n+m)!}\)。因为最终的序列是一定的,两个序列不同当且仅当权值相同的数排列方式不同。
attack
2019/03/11
3810
BZOJ1802: [Ahoi2009]checker(性质分析 dp)
题意 题目链接 Sol 一个不太容易发现但是又很显然的性质: 如果有两个相邻的红格子,那么第一问答案为0, 第二问可以推 否则第一问答案为偶数格子上的白格子数,第二问答案为偶数格子上的红格子数 #include<bits/stdc++.h> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #define fi first #define se second //#define int long long #define LL lo
attack
2019/02/26
3580
BZOJ2388: 旅行规划(分块 凸包)
题意 题目链接 Sol 直接挂队爷的题解了 分块题好难调啊qwq #include<bits/stdc++.h> #define LL long long using namespace std;
attack
2019/01/30
4460
loj#6073. 「2017 山东一轮集训 Day5」距离(费用流)
我们可以把图行列拆开,同时对于行/列拆成很多个联通块,然后考虑每个点所在的行联通块/列联通块的贡献。
attack
2019/04/01
4140
洛谷P3586 [POI2015]LOG(贪心 权值线段树)
题意 题目链接 Sol 显然整个序列的形态对询问没什么影响 设权值\(>=s\)的有\(k\)个。 我们可以让这些数每次都被选择 那么剩下的数,假设值为\(a_i\)次,则可以\(a_i\)次被选择 一个显然的思路是每次选最大的C个 那么只需要判断\(\sum a_i >=(c - k)*s\)即可 权值线段树维护一下 #include<bits/stdc++.h> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #define f
attack
2019/03/05
5520
洛谷P4170 [CQOI2007]涂色(区间dp)
裸的区间dp,\(f[l][r]\)表示干掉\([l, r]\)的最小花费,昨天写的时候比较困于是就把能想到的转移都写了。。
attack
2019/03/15
4480
BZOJ4827: [Hnoi2017]礼物(FFT 二次函数)
题意 题目链接 Sol 越来越菜了。。裸的FFT写了1h。。 思路比较简单,直接把 \(\sum (x_i - y_i + c)^2\) 拆开 发现能提出一坨东西,然后与c有关的部分是关于C的二次函数可以直接算最优取值 剩下的要求的就是\(max (\sum x_i y_i)\) 画画图就知道把y序列倒过来就是个裸的FFT了。 #include<bits/stdc++.h> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #defi
attack
2019/03/05
3140
SDOI 2018二轮题解(除Day2T1)
然鹅学了不到一个月文化课再回来看OI的东西有一种恍如隔世的感觉,烤前感觉也没啥可复习的,就补一补去年二轮的题吧。
attack
2019/05/14
5440
洛谷P2664 树上游戏(点分治)
考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献。
attack
2019/04/09
5490
洛谷P4591 [TJOI2018]碱基序列(hash dp)
题意 题目链接 Sol \(f[i][j]\)表示匹配到第\(i\)个串,当前在主串的第\(j\)个位置 转移的时候判断一下是否可行就行了。随便一个能搞字符串匹配的算法都能过 复杂度\(O(|S| K a_i)\) #include<bits/stdc++.h> #define Pair pair<int, int> #define MP(x, y) make_pair(x, y) #define fi first #define se second //#define int long long #d
attack
2019/03/19
4740
BZOJ4358: permu(带撤销并查集 不删除莫队)
想了一会儿,大概用个不删除莫队+带撤销并查集就能搞了吧,\(n \sqrt{n} logn\)应该卡的过去
attack
2019/03/05
8350
loj#6031. 「雅礼集训 2017 Day1」字符串(SAM 广义SAM 数据分治)
考虑K比较小的情况,可以直接暴力建SAM, 枚举w的子串算出现次数。询问用个 的vector记录一下每次在vector里二分就好。
attack
2019/03/19
6540
洛谷P2045 方格取数加强版(费用流)
对于拆出来的每个点,在其中连两条边,一条为费用为点权,流量为1,另一条费用为0,流量为INF
attack
2019/03/05
3570
洛谷P3247 [HNOI2016]最小公倍数(分块 带撤销加权并查集)
给出一张带权无向图,每次询问\((u, v)\)之间是否存在一条路径满足\(max(a) = A, max(b) = B\)
attack
2019/03/15
4100
推荐阅读
相关推荐
HDU4609 3-idiots(生成函数)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档