zoukankan      html  css  js  c++  java
  • Luogu4433:[COCI2009-2010#1] ALADIN(类欧几里德算法)

    先套用一个线段树维护离散化之后的区间的每一段的答案
    那么只要考虑怎么下面的东西即可

    [sum_{i=1}^{n}(A imes i mod B) ]

    拆开就是

    [sum_{i=1}^{n}A imes i-B imes sum_{i=1}^{n}lfloorfrac{A imes i}{B} floor ]

    只要考虑计算 (sum_{i=1}^{n}lfloorfrac{A imes i}{B} floor) 即可
    类欧几里德算法
    (A>B),那么就是

    [lfloorfrac{A}{B} floorsum_{i=1}^{n}i+sum_{i=1}^{n}lfloorfrac{(A mod B) imes i}{B} floor ]

    变成 (A<B) 的情况
    对于 (A<B),那么可以看成是求直线 (y=frac{A}{B} imes i,iin[1,n]) 与坐标轴围成的三角形中的整点的个数
    (m=lfloorfrac{A imes n}{B} floor)
    把问题为矩形 ((0,0),(n,m)) 内的减去三角形 ((0,0),(n,m),(0,m)) 内的再加上对角线的
    对角线上的就是 (frac{n imes gcd(A,B)}{B}),矩形内的就是 (n imes m)
    对于那个三角形的,反转坐标系后相当于是求直线 (y=frac{B}{A} imes i,iin[1,lfloorfrac{A imes n}{B} floor]) 与坐标轴围成的三角形中的整点的个数

    [sum_{i=1}^{lfloorfrac{A imes n}{B} floor}lfloorfrac{B imes i}{A} floor ]

    递归处理即可,复杂度和 (gcd) 一样
    可以先把 (A,B) 同时除去 (gcd) 后再做
    这个题注意一个细节

    [sum_{i=1}^{n}A imes i-B imes sum_{i=1}^{n}lfloorfrac{A imes i}{B} floor ]

    直接求的可能会爆 (long long)
    可以对 (B) 分段,算出长度为 (B) 的乘上 (lfloorfrac{n}{B} floor),再加上长度为 (n mod B) 的,可以接受

    # include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    namespace IO {
    	const int maxn(1 << 21 | 1);
    
    	char ibuf[maxn], *iS, *iT, c;
    	int f;
    
    	inline char Getc() {
    		return iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, maxn, stdin), (iS == iT ? EOF : *iS++)) : *iS++;
    	}
    
    	template <class Int> inline void In(Int &x) {
    		for (f = 1, c = Getc(); c < '0' || c > '9'; c = Getc()) f = c == '-' ? -1 : 1;
    		for (x = 0; c >= '0' && c <= '9'; c = Getc()) x = (x << 1) + (x << 3) + (c ^ 48);
    		x *= f;
    	}
    }
    
    using IO :: In;
    
    const int maxn(1e5 + 5);
    
    int n, m, o[maxn], cnt;
    
    struct Segment {
    	ll sum;
    	int a, b, l;
    } tr[maxn << 2];
    
    inline void Update(int x) {
    	tr[x].sum = tr[x << 1].sum + tr[x << 1 | 1].sum;
    }
    
    inline int Gcd(int a, int b) {
    	return !b ? a : Gcd(b, a % b);
    }
    
    inline ll Mul(int a, int b, int len) {
    	register int k = a / b;
    	register ll sum = 1LL * k * (len + 1) * len / 2;
    	if (!(a %= b) || !b) return sum;
    	register int m = 1LL * len * a / b;
    	assert(m >= 0);
    	return 1LL * len * m + len / b - Mul(b, a, m) + sum;
    }
    
    inline ll Calc(int a, int b, int len) {
    	if (len < 1 || a == b || b == 1) return 0;
    	register int g = Gcd(a, b);
    	return 1LL * a * len * (len + 1) / 2 - 1LL * b * Mul(a / g, b / g, len);
    }
    
    inline ll Solve(int a, int b, int len) {
    	register ll ret = Calc(a, b, len % b);
    	if (len >= b) ret += 1LL * len / b * Calc(a, b, b);
    	return ret;
    }
    
    inline void Add(int x, int a, int b, int l, int len) {
    	tr[x].a = a, tr[x].b = b, tr[x].l = l;
    	tr[x].sum = Solve(a, b, l + len - 1) - Solve(a, b, l - 1);
    }
    
    inline void Pushdown(int x, int l, int r) {
    	if (!tr[x].a) return;
    	register int mid = (l + r) >> 1;
    	Add(x << 1, tr[x].a, tr[x].b, tr[x].l, o[mid] - o[l]);
    	Add(x << 1 | 1, tr[x].a, tr[x].b, tr[x].l + o[mid] - o[l], o[r] - o[mid]);
    	tr[x].a = tr[x].b = tr[x].l = 0;
    }
    
    ll Query(int x, int l, int r, int ql, int qr) {
    	if (l >= qr || r <= ql) return 0;
    	if (ql <= l && qr >= r) return tr[x].sum;
    	Pushdown(x, l, r);
    	register int mid = (l + r) >> 1;
    	register ll ret = 0;
    	if (ql <= mid) ret = Query(x << 1, l, mid, ql, qr);
    	if (qr >= mid) ret += Query(x << 1 | 1, mid, r, ql, qr);
    	return ret;
    }
    
    void Modify(int x, int l, int r, int ql, int qr, int a, int b) {
    	if (l >= qr || r <= ql) return;
    	if (ql <= l && qr >= r) {
    		Add(x, a, b, o[l] - o[ql] + 1, o[r] - o[l]);
    		return;
    	}
    	Pushdown(x, l, r);
    	register int mid = (l + r) >> 1;
    	if (ql <= mid) Modify(x << 1, l, mid, ql, qr, a, b);
    	if (qr >= mid) Modify(x << 1 | 1, mid, r, ql, qr, a, b);
    	Update(x);
    }
    
    int op[maxn], ql[maxn], qr[maxn], a[maxn], b[maxn];
    
    int main () {
    	In(n), In(m);
    	register int i, l, r;
    	for (i = 1; i <= m; ++i) {
    		In(op[i]), In(ql[i]), In(qr[i]), --ql[i];
    		o[++cnt] = ql[i], o[++cnt] = qr[i];
    		if (op[i] == 1) In(a[i]), In(b[i]);
    	}
    	sort(o + 1, o + cnt + 1), cnt = unique(o + 1, o + cnt + 1) - o - 1;
    	for (i = 1; i <= m; ++i) {
    		l = lower_bound(o + 1, o + cnt + 1, ql[i]) - o;
    		r = lower_bound(o + 1, o + cnt + 1, qr[i]) - o;
    		if (op[i] == 1) Modify(1, 1, cnt, l, r, a[i], b[i]);
    		else printf("%lld
    ", Query(1, 1, cnt, l, r));
    	}
    	return 0;
    }
    
  • 相关阅读:
    .Net使用分布式缓存 C# 使用Redis
    微信申请退款API~~开发
    微信支付和支付宝支付分账接口文档
    Android xUtils3.0使用手册(一)- 基础功能使用
    支付宝支付开发——当面付条码支付和扫码支付
    vue开源项目汇总
    Azure和插件发布
    SqlServer数据库优化笔记
    企业微信通过PostMan获取accesstoken与管理员信息方法
    VisualStudio插件自动加载
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/9916362.html
Copyright © 2011-2022 走看看