题目链接

题意简述

区间赋值模意义下等差数列,询问区间和

\(N\leq 10^9,Q\leq 10^5\)

Sol

每次操作就是把操作区间\([L,R]\)中的数赋值成:

\[(X-L+1)*A\ mod\ B
\]

考虑用线段树维护。

我们只需要能快速知道一段区间\([l,r]\)被覆盖后的和就行了,因为覆盖的标记易于下传:

\[\sum_{i=l}^{r} (i-L+1)*A\ mod\ B
\]

根据基础的数学知识,mod显然不好算,把它拆开:

\[\sum_{i=l}^r (i-L+1)*A-\bigg\lfloor \frac{(i-L+1)*A}{B}\bigg\rfloor*B
\]

前面那一坨直接算就行了,关键是后面这一坨。我们可以把后面的式子写简洁一些:

\[B*\sum_{i=q}^{p} \bigg\lfloor \frac{A*i}{B}\bigg\rfloor
\]

其中\(p=l-L+1,q=r-l+1\),\(B\)乘在外面不用管,而\(p\)到\(q\)的求和可以拆分为\(0\sim q\) 的和减去\(0\sim p-1\)的和,这样我们只需要会算以下式子:

\[\sum_{i=0}^n \bigg\lfloor \frac{A*i}{B}\bigg\rfloor
\]

这玩意就可以用类欧几里得算法求,具体过程如下。


第一种方法是用几何的思想直观的来理解,但是似乎不是很好推出明确的式子,所以这里主要用代数推导。

对于式子:

\[\sum_{i=0}^n \bigg\lfloor \frac{A*i+B}{C}\bigg\rfloor
\]

其几何意义就是直线\(y=\dfrac{Ax+B}{C}\) 下方和x轴与y轴与直线\(x=n\)围成的图形中包含的纵坐标不为0的整点个数,这个画个图就很好理解:

\[令\ F(n,A,B,C)=\sum_{i=0}^n \bigg\lfloor \frac{A*i+B}{C}\bigg\rfloor
\]

如果 \(A,B\)不小于 \(C\),那么可以把整除的部分提出来直接计算,这个很简单,所以只讨论\(A,B\)都小于\(C\)的情况。

记\(m=\big\lfloor \frac{A*n+B}{C}\big\rfloor\),通过几何意义转换(这里方便推式子j从0到m-1):

\[F(n,A,B,C)=\sum_{i=0}^n\sum_{j=0}^{m-1} \bigg[(A*i+B) \geq C*(j+1)\bigg]
\]

调换求和顺序

\[F(n,A,B,C)=\sum_{i=0}^{m-1}\sum_{j=0}^n\bigg [(A*j+B)\geq C*(i+1)\bigg]
\]

移项变形,减1去掉不等式的等号:

\[F(n,A,B,C)=\sum_{i=0}^{m-1}\sum_{j=0}^n \bigg[(C*i+C-B-1) < A*j\bigg]
\]

接下来容斥一下,用总数减去不合法的情况:

\[F(n,A,B,C)=\sum_{i=0}^{m-1}(n+1-\sum_{j=0}^n \bigg[(C*i+C-B-1) \geq A*j\bigg])
\]

这一下里面的不就和原来我们的\(F(x)\)的形式差不多了嘛。

考虑到我们之前\(j\)是从\(0\sim m-1\)而当\(j=0\)的时候,左边必大于0,而右边为0,贡献一定存在,故可以把原式改写,先把1的贡献减在外面:

\[F(n,A,B,C)=\sum_{i=0}^{m-1}(n-\sum_{j=0}^{n-1} \bigg[(C*i+C-B-1) \geq A*(j+1)\bigg])
\]

这样不就提出\(n\)来:

\[F(n,A,B,C)=n*m-\sum_{i=0}^{m-1}\sum_{j=0}^{n-1} \bigg[(C*i+C-B-1) \geq A*(j+1)\bigg]
\]

后面的式子很先然可以根据\(F(x)\)的定义改写:

\[F(n,A,B,C)=n*m-F(m-1,C,C-B-1,A)
\]

这样递归下去不停计算,显然的是当最后\(A\)变成\(0\)的时候贡献为\(0\)

只用观察\(A\)和\(C\),发现他们调换了位置,这样必然使得下一次的\(C \leq A\),那么可以先把这部分提出来计算,实际上就是:\((A,C) \rightarrow (C\%A,A)\),这不是就是和\(gcd\)长的一样吗,所以复杂度也是\(O(logn)\)

其实类欧主要是一种把整除转化为求整点的思想

直接写类欧的代码差不多长这样:

ll likegcd(ll n,ll a,ll b,ll c){
if(c<=a||c<=b) return (a/c*n%mod*(n+1)%mod*inv2%mod+b/c*(n+1)%mod+likegcd(n,a%c,b%c,c))%mod;
if(!a||!n) return 0;
ll m=(a*n+b)/c;
return (n*m%mod-likegcd(m-1,c,c-b-1,a)+mod)%mod;
}

所以这道题也差不多做完了

但是有两个要注意的地方:

1.直接乘可能会爆\(long long\),所以\(\_\_int128\)大法好

2.本题卡空间所以要对操作区间和询问区间离散化,注意离散化的是\(l-1和r\)

代码:

#include<bits/stdc++.h>
using namespace std;
#define Set(a,b) memset(a,b,sizeof(a))
template<class T>inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}
int n,q;
//#define ll __int128
typedef long long ll;
const int MAXN=2e6+1;
const int M=5e4+1;
ll sum[MAXN];
int L[MAXN],R[MAXN];
int tagA[MAXN],tagB[MAXN],tagL[MAXN];
struct Query{
int l,r,A,B;
}Q[M];
int stk[M<<1];int top=0;
#define ls (u<<1)
#define rs (u<<1|1)
void build(int u,int l,int r){
if(l==r) {L[u]=stk[l-1]+1,R[u]=stk[r];return;}
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
L[u]=L[ls],R[u]=R[rs];return;
}
ll likegcd(ll n,ll a,ll b,ll c){
if(c<=a||c<=b) return (a/c*(n*(n+1)/2)+b/c*(n+1)+likegcd(n,a%c,b%c,c));
if(!a||!n) return 0;
ll m=(a*n+b)/c;
return n*m-likegcd(m-1,c,c-b-1,a);
}
inline void Cover(int u,int l,int r,int L,int A,int B){
int len=r-l+1;
sum[u]=1ll*(l+r-(L<<1)+2)*len/2*A-1ll*B*(likegcd(r-L+1,A,0,B)-likegcd(l-L,A,0,B));
tagA[u]=A,tagB[u]=B;tagL[u]=L;
return;
}
inline void push_down(int u){
if(tagL[u]) {
int lson=ls,rson=rs;
Cover(lson,L[lson],R[lson],tagL[u],tagA[u],tagB[u]);
Cover(rson,L[rson],R[rson],tagL[u],tagA[u],tagB[u]);
tagL[u]=tagA[u]=tagB[u]=0;
}
return;
}
void Modify(int u,int l,int r,int NL,int NR,int LS,int A,int B){
if(l>=NL&&r<=NR) return Cover(u,L[u],R[u],LS,A,B);
int lson=ls,rson=rs;push_down(u);
int mid=l+r>>1;
if(mid>=NL) Modify(lson,l,mid,NL,NR,LS,A,B);
if(mid< NR) Modify(rson,mid+1,r,NL,NR,LS,A,B);
sum[u]=sum[lson]+sum[rson];
return;
}
ll query(int u,int l,int r,int L,int R){
if(l>=L&&r<=R) return sum[u];
push_down(u);
int mid=l+r>>1;
if(mid>=R) return query(ls,l,mid,L,R);
if(mid< L) return query(rs,mid+1,r,L,R);
return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
}
int main()
{
init(n);init(q);
for(int i=1;i<=q;++i){//区间的离散化是把 l-1 和 r 离散
int op;init(op);
if(op==1){
int l,r,A,B;
init(l);init(r);init(A);init(B);
Q[i].l=l,Q[i].r=r,Q[i].A=A,Q[i].B=B;
stk[++top]=l-1,stk[++top]=r;
}
else {
int l,r;init(l);init(r);
Q[i].l=l,Q[i].r=r;
stk[++top]=l-1,stk[++top]=r;
Q[i].A=-1;
}
}
stk[0]=0;
sort(stk+1,stk+1+top);top=unique(stk+1,stk+1+top)-stk-1;
build(1,1,top);
for(int i=1;i<=q;++i){
if(Q[i].A!=-1){
int l=Q[i].l,r=Q[i].r,A=Q[i].A,B=Q[i].B;
int Li=lower_bound(stk+1,stk+1+top,l-1)-stk+1;
int Ri=lower_bound(stk+1,stk+1+top,r)-stk;
Modify(1,1,top,Li,Ri,l,A,B);
}
else printf("%lld\n",query(1,1,top,lower_bound(stk+1,stk+1+top,Q[i].l-1)-stk+1,lower_bound(stk+1,stk+1+top,Q[i].r)-stk));
}
}

【LuoguP4433】[COCI2009-2010#1] ALADIN(含类欧几里得算法推导)的更多相关文章

  1. 欧几里得(Euclid)与拓展的欧几里得算法

    欧几里得(Euclid)与拓展的欧几里得算法 欧几里得(Euclid)与拓展的欧几里得算法 欧几里得算法 原理 实现 拓展的欧几里得算法 原理 递归求解 迭代求解 欧几里得算法 原理 欧几里得算法是一 ...

  2. 扩展欧几里得算法(extgcd)

    相信大家对欧几里得算法,即辗转相除法不陌生吧. 代码如下: int gcd(int a, int b){ return !b ? gcd(b, a % b) : a; } 而扩展欧几里得算法,顾名思义 ...

  3. 欧几里得算法:从证明等式gcd(m, n) = gcd(n, m mod n)对每一对正整数m, n都成立说开去

    写诗或者写程序的时候,我们经常要跟欧几里得算法打交道.然而有没要考虑到为什么欧几里得算法是有效且高效的,一些偏激(好吧,请允许我用这个带有浓重个人情感色彩的词汇)的计算机科学家认为,除非程序的正确性在 ...

  4. noip知识点总结之--欧几里得算法和扩展欧几里得算法

    一.欧几里得算法 名字非常高大上的不一定难,比如欧几里得算法...其实就是求两个正整数a, b的最大公约数(即gcd),亦称辗转相除法 需要先知道一个定理: gcd(a, b) = gcd(b, a  ...

  5. 欧几里得算法与扩展欧几里得算法_C++

    先感谢参考文献:http://www.cnblogs.com/frog112111/archive/2012/08/19/2646012.html 注:以下讨论的数均为整数 一.欧几里得算法(重点是证 ...

  6. 最小公约数(欧几里得算法&amp;&amp;stein算法)

    求最小公约数,最easy想到的是欧几里得算法,这个算法也是比較easy理解的,效率也是非常不错的. 也叫做辗转相除法. 对随意两个数a.b(a>b).d=gcd(a.b),假设b不为零.那么gc ...

  7. vijos1009:扩展欧几里得算法

    1009:数论 扩展欧几里得算法 其实自己对扩展欧几里得算法一直很不熟悉...应该是因为之前不太理解的缘故吧这次再次思考,回看了某位大神的推导以及某位大神的模板应该算是有所领悟了 首先根据题意:L1= ...

  8. ****ural 1141. RSA Attack(RSA加密,扩展欧几里得算法)

    1141. RSA Attack Time limit: 1.0 secondMemory limit: 64 MB The RSA problem is the following: given a ...

  9. 欧几里得算法求最大公约数(gcd)

    关于欧几里得算法求最大公约数算法, 代码如下: int gcd( int a , int b ) { if( b == 0 ) return a ; else gcd( b , a % b ) ; } ...

随机推荐

  1. 错误:expected initializer before "***"

    今天写了一个程序,编译时报了一个错误:expected initializer before "***"报错的语句只是程序开头的一个变量定义语句,怎么会有这样的错误呢,琢磨了半天也 ...

  2. cocos2dx[3.2](7) 核心类Director/Scene/Layer/Sprite

    [核心类] 导演Director.场景Scene.布景层Layer.精灵Sprite的概念请移步: cocos2dx基础篇(2) 第一个程序 导演控制场景,场景控制图层,图层控制精灵,精灵控制动作. ...

  3. 【LeetCode】188、买卖股票的最佳时机 IV

    Best Time to Buy and Sell Stock IV 题目等级:Hard 题目描述: Say you have an array for which the ith element i ...

  4. Keytool生成证书

    一.生成证书keytool -genkey -alias 别名 -keyalg RSA -keysize 1024(密钥位数) -keypass 密码 -validity 365(默认90天) -ke ...

  5. jinja2模板接受

    from flask import Flask,render_template app = Flask(__name__)#template_folder='templates',默认就是templa ...

  6. XSS绕过WAF的姿势

    初始测试 1.使用无害的payload,类似<b>,<i>,<u> 观察响应,判断应用程序是否被HTML编码,是否标签被过滤,是否过滤<>等等: 2.如 ...

  7. tp5框架用foreach循环时候报Indirect modification of overloaded element of think\paginator\driver\Bootst错误

    thinkphp5使用paginator分页查询数据后,需要foreach便利处理某一字段的数据,会出现类似题目的错误.主要是因为tp5使用分页类读取的数据不是纯数组的格式!所以在循环的时候需要用数据 ...

  8. 实用且堪称神器的Chrome插件推荐(转)

    出处: http://tengj.top/2018/02/17/ggcj/ 前言 相信很多人都在使用 Chrome 浏览器,其流畅的浏览体验得到了不少用户的偏爱,但流畅只是一方面, Chrome 最大 ...

  9. 从头到尾说一次 Java 垃圾回收,写得非常好! (转)

    之前上学的时候有这个一个梗,说在食堂里吃饭,吃完把餐盘端走清理的,是 C++ 程序员,吃完直接就走的,是 Java 程序员.

  10. scrapy存储mysql

    scrapy 数据存储mysql   #spider.pyfrom scrapy.linkextractors import LinkExtractor from scrapy.spiders imp ...