等差数列除以一个数字求和(2019牛客暑期多校训练营(第九场)I题)

??神仙算法,类欧几里得的另一种用法

首先对于一个a为公差,b为首项,n为项数的等差数列,我们以c为除数
我们先考虑首项的贡献,很明显为b/c*n(还用你说 )。
然后对于公差a,我们一共也是计算了(n-1)n次(1到n-1等差数列求和),所以也很明显是
a/c
(n-1)*n。
到这里就完成一半了(根本还没开始

因为是整除,所以接下来我们考虑加起来而导致的溢出情况(a 我们将a和b对c取模再求一次便可以了,取模后所有的答案都是溢出造成的
首先我们考虑和(an+b)/c商一样的数有几个(这个商我们设为x),很明显是((an+b)%c)/a。(从an+b一次减个a,看能减几次商不变)
然后我们再考虑商大于等于x-k的数有几个,同样的算法很容易得到是((a
n+b)%c+kc)/a个。
我们一直算到商大于等于1的就可以得到最后的答案。
((a
n+b)%c)/a ((an+b)%c+kc)/a 仔细看看这两个式子是不是很眼熟。
c为公差 (an+b)%c为首项 a为除数 (an+b)/c为项数,所以开始快乐的 欧几里得算法吧。

代码我贴出来了

// 求a 公差 b 首项 c 除数 n 项数       等差数列除以一个数字(2的次幂)求和
ll get(__int128 a,__int128 b,__int128 c,__int128 n){
    if (n<=0) return 0;
    if (n==1) return (b/c)%mod;
    __int128 tmp=(a/c%mod*(n-1)%mod*n%mod*inv[2]%mod+b/c*n)%mod;
    a=a%c;
    b=b%c;
    if(a==0)return tmp;
    return (tmp+get(c,(a*n+b)%c,a,(a*n+b)/c))%mod; //(a*n+b)%c/a 为大于等于(a*n+b)/b的商有多少个 
}

有了这个这题就很好做了,记得别爆long long和mod要用逆元

你可能感兴趣的:(数论)