• 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;
    }
    
  • 相关阅读:
    [原]跟我学silverlight系列教程[1]—wpf/silverlight体系架构和运行机制
    [转载]My97DatePicker在Frame中无法打开站点
    sql select的时候按特定的顺序排序
    javascript获取滚动条位置
    sql2005 数据库没有完全关闭,无法重新生成日志
    .Net framework
    输出datagrid的内容到excel
    IIS中网站出错
    [原]跟我学silverlight系列教程
    SharePoint2010 的ADFS2.0设置
  • 原文地址:https://www.cnblogs.com/dmoransky/p/12602313.html
Copyright © 2020-2023  润新知