zoukankan      html  css  js  c++  java
  • BJOI2016 回转寿司

    题目链接

    Description

    给定一个长度为 (N) 的序列 (a),和一个区间 ([L, R])

    求多少连续子序列的权值和在区间内,即满足 (1 le i le j le n) 且满足 (L le sum_{k=i}^{j} a[i] le R) 的方案数。

    Solution

    区间和,很容易想到用前缀和转换,这样区间相关变成了两个点。设 (s)(a) 的前缀和,那么统计就变成了这样。

    统计 (0 le i < j le n) 中满足 (L le s[j] - s[i] le R) 的方案数的。数据只有一组询问,显然是支持我们枚举一维,的不妨枚举 (s[i]),那么转化一下式子,就是满足 (L + s[i] le s[j] le R + s[i])(i < j)(j) 的数量。

    这就是一个显然的二维偏序问题,做法就是:

    • 倒序枚举 (i)
    • 查询答案
    • 插入 (s[i])

    单调修改、区间查询这个操作我们再熟悉不过了。但是这次因为离散化会把值域信息搞没,所以不能离散化,只能动态开点线段树。(后来想了一下好像也可以,把数值全部打进数组离散化一下,所以写了两个版本)。

    时间复杂度

    (O(nlog_2 10^{10}))

    Code

    动态开点线段树版

    #include <iostream>
    #include <cstdio>
    
    using namespace std;
    
    typedef long long LL;
    
    const int N = 100005;
    
    int n, L, R, rt, idx;
    
    struct T{
    	int l, r, v;
    } t[N * 30];
    
    LL Lt = 9e18, Rt = -9e18;
    
    LL s[N], ans = 0;
    
    void inline pushup(int p) {
    	t[p].v = t[t[p].l].v + t[t[p].r].v;
    }
    
    void insert(int &p, LL l, LL r, LL x) {
    	if (!p) p = ++idx;
    	t[p].v++;
    	if (l == r) return;
    	LL mid = (l + r) >> 1;
    	if (x <= mid) insert(t[p].l, l, mid, x);
    	else insert(t[p].r, mid + 1, r, x);
    }
    
    int query(int p, LL l, LL r, LL x, LL y) {
    	if (!p) return 0;
    	if (x <= l && r <= y) return t[p].v;
    	LL mid = (l + r) >> 1, res = 0;
    	if (x <= mid) res += query(t[p].l, l, mid, x, y);
    	if (mid < y) res += query(t[p].r, mid + 1, r, x, y);
    	return res;
    }
    
    int main() {
    	scanf("%d%d%d", &n, &L, &R);
    	for (int i = 1; i <= n; i++) scanf("%lld", &s[i]), s[i] += s[i - 1];
    	for (int i = 1; i <= n; i++) {
    		Lt = min(Lt, s[i]);
    		Rt = max(Rt, R + s[i]);
    	}
    	for (int i = n; ~i; i--) {
    		ans += query(rt, Lt, Rt, L + s[i], R + s[i]);
    		if (i) insert(rt, Lt, Rt, s[i]);
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    

    树状数组版

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    
    const int N = 100005;
    
    int n, L, R, tot, c[N];
    
    LL s[N], d[N], ans = 0;
    
    int inline get(LL x) {
    	return lower_bound(d + 1, d + 1 + tot, x) - d;
    }
    
    void inline add(int x) {
    	for (; x <= tot; x += x & -x) c[x]++;
    }
    
    int inline ask(int x) {
    	int res = 0;
    	for (; x; x -= x & -x) res += c[x];
    	return res;
    }
    
    int main() {
    	scanf("%d%d%d", &n, &L, &R);
    	for (int i = 1; i <= n; i++) 
    		scanf("%lld", &s[i]), s[i] += s[i - 1], d[++tot] = s[i];
    	sort(d + 1, d + 1 + tot);
    	tot = unique(d + 1, d + 1 + tot) - d - 1;
    	for (int i = n; ~i; i--) {
    		int A = lower_bound(d + 1, d + 1 + tot, L + s[i]) - d - 1; 
    		int B = upper_bound(d + 1, d + 1 + tot, R + s[i]) - d - 1; 
    		ans += ask(B) - ask(A);
    		if (i) add(get(s[i]));
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    手把手教你利用create-nuxt-app脚手架创建NuxtJS应用
    初识NuxtJS
    webpack打包Vue应用程序流程
    用选择器代替表格列的筛选功能
    Element-UI
    Spectral Bounds for Sparse PCA: Exact and Greedy Algorithms[贪婪算法选特征]
    Sparse Principal Component Analysis via Rotation and Truncation
    Generalized Power Method for Sparse Principal Component Analysis
    Sparse Principal Component Analysis via Regularized Low Rank Matrix Approximation(Adjusted Variance)
    Truncated Power Method for Sparse Eigenvalue Problems
  • 原文地址:https://www.cnblogs.com/dmoransky/p/12602313.html
Copyright © 2011-2022 走看看