Loading

模版类欧几里得

模版类欧几里得

这个东西,说他没用,确实极少会见到。去推这个柿子也完全是因为兴趣(顺便练习一下推柿子的能力),整体来说,这个推柿子难度不高,基本上有小学知识就能够理解。

这里知有代数解法,几何意义本人太菜了还不会。

Base 题目

给定 n,a,b,c ,分别求 i=0nai+bc, i=0nai+bc2, i=0niai+bc

Part If

先来讨论第一个,在这里我们设其为 f,更具体的,有

f(a,b,c,n)=x=0nax+bc

(这里用 x 主要是笔者本人觉得 ai 有时候会错看成数组下标)

主要套路有两个:取模和化贡献。

取模

取模意义在于能够把 a,bc 化为 a,b<c 的形式。

显然有 α=αmodβ+(ααmodβ),直接暴力拆开来。

f(a,b,c,n)=x=0n(amodc)x+(aamodc)x+(bmodc)+(bbmodc)c

发现第二项和第四项都是可以整除 c 的,因此可以直接提出来。

=x=0n(amodc)x+(bmodc)c+(aamodc)x+(bbmodc)c=x=0n(amodc)x+(bmodc)c+acx+bc

前面的东西就是 f(amodc,bmodc,c,n) 第二个可以求和提出来,最后一项直接提出来就好,因此我们有了如下式子:

f(a,b,c,n)=n(n+1)2ac+(n+1)bc+f(amodc,bmodc,c,n)

化贡献

接下来考虑如何快速计算一个 f

我们把 ax+bc 看成这样一个东西:j=0ax+bc1,这样做的原因主要是为了能够凑出来一种递归的形式(其实我也不太清楚,也只能这样解释了)。带入 + 交换求和顺序有:

f(a,b,c,n)=x=0nj=0ax+bc11=j=0an+bc1x=0n[j<ax+bc]

为了方便,设 m=an+bc,然后对于后面的东西,我们希望条件是和 x 相关的(这样就可以丢掉一个求和符号)。因为 j 是整数,可以这样化简:

j<ax+bcj+1ax+bcj+1ax+bcjc+cax+bxjc+cbaxjc+cbax>jc+cb1a

最后一步是因为我们接下来要用到大于的形式比较好化简。代回原式有

=j=0m1x=0n[x>jc+cb1a]=j=0m1(njc+cb1a)=nmj=0m1jc+cb1a=nmf(c,cb1,a,m1)

这样就成功形成一个递归的形式了,观察到这个递归形式很像 gcd 算法,所以大佬们取名叫做类欧几里得。

Part IIg,h

这两个需要一起解,先设

g(a,b,c,n)=x=0nxax+bch(a,b,c,n)=x=0nax+bc2

注意和原题面的顺序不太一样。

g

老套路来一遍,就不加注释了

g(a,b,c,n)=x=0nxax+bc=x=0nx(amodc)x+(aamodc)x+(bmodc)+(bbmodc)c=x=0nx(amodc)x+(bmodc)c+acx2+bcx=n(n+1)(2n+1)6ac+n(n+1)2bc+g(amodc,bmodc,c,n)

得到几乎一摸一样的取模形式。

具体计算也先尝试一样的套路试一下

g(a,b,c,n)=j=0m1x=0nx[x>jc+cb1a]

这时候出现了一点小问题,后面多了一个 x 如何处理?设 t=jc+cb1a,我们可以调整一下求和范围把后面的东西干掉,即

=j=0m1x=t+1nx=j=0m1(n+t+1)(nt)2=12j=0m1n(n+1)t(t+1)=12(j=0m1n(n+1)j=0m1(t2+t))=12(mn(n+1)j=0m1t2j=0m1t)

回忆一下 t=jc+cb1a,后面两项都可以化成我们已有的函数,即有了

g(a,b,c,n)=12(mn(n+1)h(c,cb1,a,m1)f(c,cb1,a,m1))

h

再来一遍!不过这次有一丢丢复杂。

h(a,b,c,n)=x=0n((amodc)x+(bmodc)c+acx+bc)2

s=(amodc)x+(bmodc)c 大力展开

=x=0n(s2+ac2x2+bc2+2acsx+2bcs+2acbc)=n(n+1)(2n+1)6ac2+(n+1)bc2+n(n+1)acbc+x=0ns2+2acx=0nxs+2bcx=0ns=n(n+1)(2n+1)6ac2+(n+1)bc2+n(n+1)acbc+h(amodc,bmodc,c,n)+2acg(amodc,bmodc,c,n)+2bcf(amodc,bmodc,c,n)

那么只剩下最后一步了,还是尝试老套路,我们利用一个看起来很废话的东西:

α2=α(α+1)2×2α

进行推导

h(a,b,c,n)=x=0n(2j=0m1(j+1)m)=2x=0nj=0m1(j+1)f(a,b,c,n)=2j=0m1(j+1)x=0n[x>t]f(a,b,c,n)=2j=0m1(j+1)(nt)f(a,b,c,n)=mn(m+1)2g(c,cb1,a,m1)2f(c,cb1,a,m1)f(a,b,c,n)

收工!

代码比较丑

#include<bits/stdc++.h>
using namespace std;
#define int long long 
int mod=998244353;
int qpow(int x,int y){
    int res=1;
    for(;y;y>>=1){
        if(y&1)res=res*x%mod;
        x=x*x%mod;
    }
    return res;
}
int inv2=qpow(2,mod-2),inv6=qpow(6,mod-2);
struct node{
    int f,g,h;
};
node calc(int a,int b,int c,int n){
    node res,tmp;
    if(a==0){
        res.f=(n+1)*(b/c)%mod;
        res.g=n*(n+1)%mod*inv2%mod*(b/c)%mod;
        res.h=(n+1)*(b/c)%mod*(b/c)%mod;
        return res;
    }
    if(a>=c||b>=c){
        tmp=calc(a%c,b%c,c,n);
        res.f=((n*(n+1)%mod*inv2%mod*(a/c)+(n+1)*(b/c)%mod)%mod+tmp.f)%mod;
        res.g=((n*(n+1)%mod*(2*n+1)%mod*inv6%mod*(a/c)%mod
        +n*(n+1)%mod*inv2%mod*(b/c)%mod)%mod
        +tmp.g)%mod;
        res.h=((((n*(n+1)%mod*(2*n+1)%mod*inv6%mod*(a/c)%mod*(a/c)%mod
        +(n+1)*(b/c)%mod*(b/c)%mod)%mod
        +n*(n+1)%mod*(a/c)%mod*(b/c)%mod)%mod
        +tmp.h+2*(a/c)%mod*tmp.g%mod)%mod
        +2*(b/c)%mod*tmp.f%mod)%mod;
        return res;
    }
    int m=((a*n)+b)/c;
    tmp=calc(c,c-b-1,a,m-1);
    res.f=(n*m%mod-tmp.f+mod)%mod;
    res.g=((n*m%mod*(n+1)%mod-tmp.h+mod)%mod-tmp.f+mod)%mod*inv2%mod;
    res.h=(((n*m%mod*(m+1)%mod-2*tmp.g%mod+mod)%mod-2*tmp.f%mod+mod)%mod-res.f+mod)%mod;
    return res;
}
int T,A,B,C,N;
signed main(){
    cin.tie(0),cout.tie(0),ios::sync_with_stdio(false);
    cin>>T;
    while(T--){
        cin>>N>>A>>B>>C;
        node R=calc(A,B,C,N);
        cout<<R.f<<" "<<R.h<<" "<<R.g<<"\n";
    }
    return 0;
}
posted @   Jryno1  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示