[COCI2009-2010#1] ALADIN

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

题目描述很简单,就是要求我们计算 ∑ i = 1 n i × A   m o d   B \sum\limits_{i=1}^ni×A\ {\rm mod}\ B i=1ni×A mod B,但是仔细思考会发现 ∑ i = 1 n i × A   m o d   B ≠ ( ∑ i = 1 n i × A )   m o d   B \sum\limits_{i=1}^ni×A\ {\rm mod}\ B≠\left(\sum\limits_{i=1}^ni×A\right)\ {\rm mod}\ B i=1ni×A mod B=(i=1ni×A) mod B,但是根据取模的实质可以知道 ∑ i = 1 n i × A   m o d   B = ∑ i = 1 n i × A − ∑ i = 1 n ⌊ i × A B ⌋ × B \sum\limits_{i=1}^ni×A\ {\rm mod}\ B=\sum\limits_{i=1}^ni×A-\sum\limits_{i=1}^n\left\lfloor\frac{i×A}{B}\right\rfloor×B i=1ni×A mod B=i=1ni×Ai=1nBi×A×B,现在的问题就是如何求出 ∑ i = 1 n ⌊ i × A B ⌋ \sum\limits_{i=1}^n\left\lfloor\frac{i×A}{B}\right\rfloor i=1nBi×A,下面将给出应该能看懂的推导。

本题难在求公差为1的等差数列乘一个数再除以一个数向下取整的和,写成公式:

∑ i = 1 n ⌊ i × q p ⌋ \sum_{i=1}^n\left\lfloor\frac{i×q}{p}\right\rfloor i=1npi×q

直接变换公式好像没什么用,那么我们就尝试将其转换到笛卡尔坐标系中来看(不要问怎么想到的,这是别人给我讲的,应该是一个技巧吧),那么对于一个点 ( i , i × q p ) (i,\frac{i×q}{p}) (i,pi×q) ⌊ i × q p ⌋ \left\lfloor\frac{i×q}{p}\right\rfloor pi×q的值就转换成了点 ( i , 0 ) (i,0) (i,0)到点 ( i , i × q p ) (i,\frac{i×q}{p}) (i,pi×q)之间有多少个整点。那么对于给定的 n , q , p n,q,p n,q,p,答案就变成了求出由直线 y = q p x , x = n , y = 0 y=\frac{q}{p}x,x=n,y=0 y=pqx,x=n,y=0三条直线所围成的一个直角三角形中有多少个整点( y = q p x , x = n y=\frac{q}{p}x,x=n y=pqx,x=n上的整点也要计入答案, y = 0 y=0 y=0上的整点不计入答案),例如当 n = 4 , q = 3 , p = 4 n=4,q=3,p=4 n=4,q=3,p=4的时候,如图所示:

在这里插入图片描述

观察图片就能知道答案为 6 6 6,那么现在的问题就是如何求出整点个数。以上面为例,看起来好像直接求出 3 × 4 3×4 3×4的网格里有多少个整点,然后除以 2 2 2再加上对角线上的点就能得到答案,但是事实并非如此,因为三角形的高是一个小数,用上面方法求解时候只用了整数部分,而且点的分布并不是中心对称的,以 n = 5 , q = 4 , p = 7 n=5,q=4,p=7 n=5,q=4,p=7为例:

在这里插入图片描述

其中实线为正确的分界,可以发现两边的点分布不均匀,虚线为错误方法认为的分界,与正确分界的答案不一样,所以上面的方法并不正确。

那么下面就要讲一个比较神奇的方法,我也不知道他们是怎么想到的,总之就当成结论记下就好。

1. q ≥ p q≥p qp

以直线 y = q p x , y = q   m o d   p p x , x = n y=\frac{q}{p}x,y=\frac{q\ {\rm mod}\ p}{p}x,x=n y=pqx,y=pq mod px,x=n所围成的三角形里的整点个数为一个等差数列,个数为 n × ( n + 1 ) 2 ⌊ q p ⌋ \frac{n×(n+1)}{2}\left\lfloor\frac{q}{p}\right\rfloor 2n×(n+1)pq,证明:

我们将 q p \frac{q}{p} pq转换成带分数的形式 v k p v\frac{k}{p} vpk,可以知道 k = q   m o d   p , v = ⌊ q p ⌋ k=q\ {\rm mod}\ p,v=\left\lfloor\frac{q}{p}\right\rfloor k=q mod p,v=pq,对于上面所说的三角形里整点的个数就是以下公式:

∑ i = 1 n ⌊ i × q p ⌋ − ⌊ i × k p ⌋ = ∑ i = 1 n ⌊ i × v + i × k p ⌋ − ⌊ i × k p ⌋ \sum\limits_{i=1}^n\left\lfloor i×\frac{q}{p}\right\rfloor-\left\lfloor i×\frac{k}{p}\right\rfloor=\sum\limits_{i=1}^n\left\lfloor i×v+i×\frac{k}{p}\right\rfloor-\left\lfloor i×\frac{k}{p}\right\rfloor i=1ni×pqi×pk=i=1ni×v+i×pki×pk

对于第一个向下取整,因为 i × v i×v i×v必定为整数,所以向下取整只是对 i × k p i×\frac{k}{p} i×pk产生影响,所以公式就可以变为下面这种样子:

∑ i = 1 n i × v + ⌊ i × k p ⌋ − ⌊ i × k p ⌋ = ∑ i = 1 n i × v \sum\limits_{i=1}^ni×v+\left\lfloor i×\frac{k}{p}\right\rfloor-\left\lfloor i×\frac{k}{p}\right\rfloor=\sum\limits_{i=1}^ni×v i=1ni×v+i×pki×pk=i=1ni×v

所以对于新三角形中整点个数为: n × ( n + 1 ) 2 v = n × ( n + 1 ) 2 ⌊ q p ⌋ \frac{n×(n+1)}{2}v=\frac{n×(n+1)}{2}\left\lfloor\frac{q}{p}\right\rfloor 2n×(n+1)v=2n×(n+1)pq

下面给一个以 n = 5 , q = 11 , p = 5 n=5,q=11,p=5 n=5,q=11,p=5为例的图片,其中虚线为直线 y = q   m o d   p p x y=\frac{q\ {\rm mod}\ p}{p}x y=pq mod px,蓝色点为减掉的点:

在这里插入图片描述

那么我们现在就只需要求用直线 y = q   m o d   p p x , y = 0 , x = n y=\frac{q\ {\rm mod}\ p}{p}x,y=0,x=n y=pq mod px,y=0,x=n所围成的三角形里的整点个数,这正好就是我们原本需要求的三角形的三边形式,也就是说我们可以考虑递归求解,直到 q   m o d   p = 0 q\ {\rm mod}\ p=0 q mod p=0,就可以算出所有的整点,但是只有 q ≥ p q≥p qp时能进行上面的操作,操作一次后 q < p q<p q<p,然后上面的操作也不能用了,这时候就需要用到下面所讨论的方法。

2. q < p q<p q<p

n = 5 , q = 4 , p = 7 n=5,q=4,p=7 n=5,q=4,p=7为例(注意:我们需要计算的整点是在右下角的三角形里,但是为了方便讲解,这里将其补成了一个矩形):

在这里插入图片描述

虽然现在看起来不能用上面的方法做,但是如果我们将图像进行翻折,好像就可以继续使用上面的方法了。

在这里插入图片描述

不过观察图片可以发现翻折后不仅需要计算的点的位置发生改变,而且下底还不是整数,使得上面的方法依然不能用,这时候就需要用到补集转化的思想,也就是求出所有点再减去不合法的点,不过因为斜边上的点也是在答案中的,所以还要加上被减掉的斜边上的点。

在这里插入图片描述

观察图片可以看到不合法的点就是虚线所围成的三角形里的点,而且这个三角形有一个好处就是下底是整数,根据翻折之前的图片来看,它的底边长度为 ⌊ n × q p ⌋ \left\lfloor\frac{n×q}{p}\right\rfloor pn×q,那么现在就变成了求出由直线 y = p q x , x = ⌊ n × q p ⌋ , y = 0 y=\frac{p}{q}x,x=\left\lfloor\frac{n×q}{p}\right\rfloor,y=0 y=qpx,x=pn×q,y=0(注意第一个直线解析式因为图像的翻折使得 p , q p,q p,q分子分母的位置发生了交换)三条直线所围成的一个直角三角形中有多少个整点,这样就可以递归算下去了。

那么斜边上的点怎么算?根据斜边的直线解析式 y = q p x y=\frac{q}{p}x y=pqx可以知道当 x x x p p p的倍数的时候才是整点,但是 q , p q,p q,p可能可以约分,所以更准确的来说,斜边上的整点个数为: ⌊ n p g c d ( p , q ) ⌋ = ⌊ n × g c d ( p , q ) p ⌋ \left\lfloor\frac{n}{\frac{p}{gcd(p,q)}}\right\rfloor=\left\lfloor\frac{n×gcd(p,q)}{p}\right\rfloor gcd(p,q)pn=pn×gcd(p,q),那么现在所有的问题都解决了。

3.时间复杂度

g e t v a l ( a , b , c ) getval(a,b,c) getval(a,b,c)表示求当 n = a , q = b , p = c n=a,q=b,p=c n=a,q=b,p=c时三角形的整点个数,那么上面的讲解可以大概分成下面几个判断:

1.若 b ≥ c b≥c bc,答案为 a × ( a + 1 ) 2 ⌊ b c ⌋ + g e t v a l ( a , b   m o d   c , c ) \frac{a×(a+1)}{2}\left\lfloor\frac{b}{c}\right\rfloor+getval(a,b\ {\rm mod}\ c,c) 2a×(a+1)cb+getval(a,b mod c,c)

2.若 b < c b<c b<c,答案为 a × ⌊ a × b c ⌋ − g e t v a l ( ⌊ a × b c ⌋ , c , b ) + ⌊ a × g c d ( b , c ) c ⌋ a× \left\lfloor\frac{a×b}{c}\right\rfloor-getval(\left\lfloor\frac{a×b}{c}\right\rfloor,c,b)+\left\lfloor\frac{a×gcd(b,c)}{c}\right\rfloor a×ca×bgetval(ca×b,c,b)+ca×gcd(b,c)

3.若 b = 0 b=0 b=0,答案为 0 0 0

观察 b , c b,c b,c的变化,这不就是类似于求 g c d gcd gcd的过程吗,因为中途也需要计算 g c d gcd gcd来求斜边上的点,所以这种方法的时间复杂度最坏是 ( l o g   m a x ( q , p ) ) 2 ({\rm log}\ max(q,p))^2 (log max(q,p))2的。

可以先练一练:整点与质数

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL mod=1e9+7;
int T;LL n,m;
LL power(LL v,LL p)
{
    LL ans=1;
    for(;p;p>>=1,v=v*v%mod)
     if(p&1)ans=ans*v%mod;
    return ans;
}
LL gcd(LL a,LL b)
{
    if(!b)return a;
    return gcd(b,a%b);
}
LL getval(LL n,LL a,LL b)
{
    if(a%b==0)return (n*(n+1)/2)*(a/b);
    if(a<b)return n*(n*a/b)-getval(n*a/b,b,a)+n*gcd(a,b)/b;
    return (n*(n+1)/2)*(a/b)+getval(n,a%b,b);
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        printf("%lld\n",(getval(n/2,m,n)%mod+(n-1)*(m-1)%mod*power(2,mod-2)%mod)%mod);
    }
    return 0;
}

[COCI2009-2010#1] ALADIN

现在这道题就变得很简单了,只需要离散化一下,然后用线段树来维护,核心的东西在上面都已经证明了,还有注意一下代码里的 g e t s u m getsum getsum函数才是上面提到的 g e t v a l getval getval函数。时间复杂度最坏 O ( n ( l o g n ) 3 ) O(n({\rm log}n)^3) O(n(logn)3)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=50010;
int n,m,tot,uni[N*2];
struct ins
{
    int pd,l,r,a,b;
}ask[N];
struct segment
{
    int l;
    long long sum,a,b;
}seg[N*8];
long long gcd(long long a,long long b)
{
    if(!b)return a;
    return gcd(b,a%b);
}
long long getsum(long long v,long long a,long long b)
{
    if(a%b==0)return (v*(v+1)/2)*(a/b);
    if(a<b)return (a*v)/b*v-getsum((a*v)/b,b,a)+v*gcd(a,b)/b;
    return v*(v+1)/2*(a/b)+getsum(v,a%b,b);
}
long long getval(long long v,long long a,long long b)
{
    return v*(v+1)/2*a-getsum(v,a,b)*b;
}
long long slove(int o,int l,int r,int l1,int a,int b)
{
    seg[o].a=a;seg[o].b=b;seg[o].l=l1;
    l=uni[l]-1;r=uni[r+1]-1;
    seg[o].sum=getval(r-uni[l1]+1,a,b);
    seg[o].sum-=getval(l-uni[l1]+1,a,b);
}
void pushdown(int o,int mid,int l,int r)
{
    if(!seg[o].a)return;
    slove(o*2,l,mid,seg[o].l,seg[o].a,seg[o].b);
    slove(o*2+1,mid+1,r,seg[o].l,seg[o].a,seg[o].b);
    seg[o].a=seg[o].b=seg[o].l=0;
}
void update(int o,int l,int r,int l1,int l2,long long a,long long b)
{
    if(l1<=l&&r<=l2)
    {
        slove(o,l,r,l1,a,b);
        return;
    }
    int mid=l+r>>1;pushdown(o,mid,l,r);
    if(l1<=mid)update(o*2,l,mid,l1,l2,a,b);
    if(mid<l2)update(o*2+1,mid+1,r,l1,l2,a,b);
    seg[o].sum=seg[o*2].sum+seg[o*2+1].sum;
}
long long find(int o,int l,int r,int l1,int l2)
{
    if(l1<=l&&r<=l2)return seg[o].sum;
    int mid=l+r>>1;
    long long ans=0;
    pushdown(o,mid,l,r);
    if(l1<=mid)ans+=find(o*2,l,mid,l1,l2);
    if(mid<l2)ans+=find(o*2+1,mid+1,r,l1,l2);
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&ask[i].pd);
        if(ask[i].pd==1)scanf("%d%d%d%d",&ask[i].l,&ask[i].r,&ask[i].a,&ask[i].b);
        else scanf("%d%d",&ask[i].l,&ask[i].r);
        uni[++tot]=ask[i].l;
        uni[++tot]=ask[i].r+1;
    }
    sort(uni+1,uni+tot+1);
    tot=unique(uni+1,uni+tot+1)-uni-1;
    uni[++tot]=n+1;
    for(int i=1;i<=m;i++)
    {
        int l1=lower_bound(uni+1,uni+tot+1,ask[i].l)-uni;
        int l2=upper_bound(uni+1,uni+tot+1,ask[i].r)-uni-1;
        if(ask[i].pd==1)
         update(1,1,tot,l1,l2,ask[i].a,ask[i].b);
        else
         printf("%lld\n",find(1,1,tot,l1,l2));
    }
    return 0;
}
CANopen实战:5分钟搞定伺服电机同步控制(附CSP模式配置步骤) 本文详细介绍了如何利用CANopen协议的周期性同步位置模式快速实现伺服电机同步控制。通过解析CSP模式的核心原理,并提供从硬件配置、对象字典设置到PDO映射的完整步骤,帮助工程师在5分钟内构建稳定可靠的多轴同步系统,大幅提升工业自动化设备的控制精度与效率。 阅读详情

相关推荐

COCI模拟考试心得体会

今天考了一场COCI的比赛,感觉题目没考什么特别难的算法,但是有些题就实现很麻烦。 第一题键盘打字,就是个打表题,打了我好大半天,还好没打错。 第二题一群固执的老人看电视,模拟一下谁去换台,换了什么台就可以过了,注意有循环就输出-1 第三题building,一道卡格式的题,给出每个矩形的左下角右上角坐标,让你勾勒整个透视图的轮廓。我想的是从外围跑一次flood fill,能够接触到的矩形的边

AZUI _ oi memories 1126

Luogu4433:[COCI2009-2010#1] ALADIN(类欧几里德算法)

先套用一个线段树维护离散化之后的区间的每一段的答案 那么只要考虑怎么下面的东西即可 \[\sum_{i=1}^{n}(A\times i \ mod \ B)\] 拆开就是 \[\sum_{i=1}^{n}A\times i-B\times \sum_{i=1}^{n}\lfloor\frac{A\times i}{B}\rfloor\] 只要考虑计算 \(\sum_{i=1}^{n}\lfloo...

weixin_34365417的博客 244

克罗地亚信息学奥赛COCI2009/2010 contest #1

克罗地亚信息学奥赛COCI2009/2010 contest #1 PDF版

【LuoguP4433】[COCI2009-2010#1] ALADIN(含类欧几里得算法推导)

题目链接 题意简述 区间赋值模意义下等差数列,询问区间和 N≤109,Q≤105N\leq 10^9,Q\leq 10^5N≤109,Q≤105 Sol 每次操作就是把操作区间[L,R][L,R][L,R]中的数赋值成: (X−L+1)∗A&nbsp;mod&nbsp;B(X-L+1)*A\ mod\ B(X−L+1)∗A&nbsp;mod&nbsp;B 考虑用线段树维护。 我们只需要能快速知道一...

Yu Gi Oh! 750

COCI2021-2022#1 Logičari

### 题目大意 给你一个有$n$个点的基环树,现在对这个基环树上的点染色,使得每个点都有且仅有一个与它相连的点(不包括他自己)被染色,求最少的染色点数。如果不存在染色方案,则输出$-1$。

tanjunming2020的博客 588

洛谷P4433 [COCI2009-2010#1] ALADIN

第一行有两个数字 𝑛n(1≤𝑛≤1091≤n≤109),𝑞q (1≤𝑞≤5×1041≤q≤5×104)。对于每个第二种操作,输出石头总数。接下来 𝑞q 行表示询问操作。

songci2013的博客 745

Luogu 4433 [COCI2009-2010#1] ALADIN

LOJ 2958 线段树 +类欧 主要矛盾就是$\sum\limits_{i = l}^{r}Ai \mod B$怎么做。 拆成前缀和相减的形式,有 $$\sum_{i = 0}^{r}(Ai \mod B) - \sum_{i = 0}^{l - 1}(Ai \mod B)$$ 我们知道 $$a \mod b = a - \left \lfloor \frac{a}{b}...

dashu497731727的博客 244

题解:P4433 [COCI 2009/2010 #1] ALADIN

iL∑R​A×imodBi0∑R​A×imodB−i0∑L−1​A×imodBi0∑N​A×imodB注意到这个取模非常烦,想一下怎么把取模去掉,注意到amodb等价于a−b×⌊ba​⌋i0∑N​A×i−B×⌊BA×i​⌋)接下来就比较简单了,把前面A×i的部分提出来,后面的−B2NN1​A−Bi0∑N​⌊BA×i​。

Benny_250的博客 248

P4433 [COCI2009-2010#1] ALADIN

题目描述 给你 n 个盒子,有 q 个操作,操作有两种: 第一种操作输入格式为"1 L R A B",表示将编号为L到R的盒子里的石头数量变为(X−L+1)×A mod B,其中 X为盒子的编号。 第二种操作输入格式为"2 L R",表示查询编号为L到R的盒子里的石头总数。 输入输出格式 输入格式: 第一行有两个数字n(1≤N≤109),q(1≤Q≤5000...

weixin_30706507的博客 248

类欧几里得算法学习笔记

类欧算法的原理及其模板的简单讲解。

TimeTraveller-VictoryCzt 1024

COCI试后心得

今天考了COCI的几个题目,考出来,成绩简直见不得人。这几个月来一直都在不停地考试,然而我并没有什么进展,考试成绩也很不理想。这是一个很严肃的问题,如果不能及时得到解决,我拿什么来面对今年的NOIP。我目前身上的问题特别多,主要是代码实现与思维方面的问题(好像我们也只用到这两个方面……),急待解决。代码实现一直是我的老问题,经常犯一些低级错误,比如变量名打错;还有很多已经有固定模式的代码打不出来,

至圣三者 992

其他国家OI比赛

以下内容摘自OI-WIKI。 USACO 美国中学生信息学比赛。USACO 或许是国内选手最熟悉的外国 OI 竞赛(因此可能也是中文题解最多的外国 OI 竞赛)。每年冬季到初春,USACO 会每月举办一场网络赛。一场比赛持续 3 ~ 5 个小时。根据官网的介绍,USACO 的比赛分成这 4 档难度(2015~2016 学年之前为 3 档): 铜牌组,适合编程初学者,尤其是只学了最最基础的算法...

努力中的老周的专栏 1万+

COKOLADA

顾客急需大小为K个单位的巧克力,但现在你大小为2的非负整数幂(即124816⋯)的巧克力进行购买。为了满足顾客需求,可以采取切割的方式,将一块大小为D个单位的巧克力切成两块大小为2D​个单位的巧克力。为了降低成本,你需要求出所需的巧克力大小的最小值和最小切割次数。

Pretty Boy Fox的博客 1277

洛谷 P8074 [COCI2009-2010#7] SVEMIR 题解

得到两点之间的距离,两点距离的因素只有 x || y || z ,所以只需要将x,y,z,分别按点的坐标从小到大sort。分别建边,所以一共只有 3(n-1)边,绝对不会TLE或MLE。此题若要Kruskal 存图 ,需要建造 Cn 2 条边,n

weixin_42178241的博客 636
上一篇: [JLOI2013]卡牌游戏
下一篇: 中国剩余定理及其扩展
hdxrie
博客等级 码龄9年 6粉丝 5原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值