LOJ 2409「THUPC 2017」小 L 的计算题 / Sum

本文详细解析了使用分治算法与NTT(离散傅立叶变换)解决复杂数学问题的过程,通过定义和变换函数,实现了在O(nlog²n)时间内高效求解。代码实现覆盖了多项式乘法、逆元计算等关键步骤。

思路

和玩游戏一题类似
定义\(A_k(x)=\sum_{i=0}^\infty a_k^ix^i=\frac{1}{1-a_kx}\)

\(\ln 'x\)代替\(\frac{1}{x}\)

所以就是求
\[ f(x)=\sum_{i=1}^n \ln'(1-a_ix) \]
这样没法快速计算

所以再设\(G(x)=\sum _{i=1}^n (ln(1-a_ix))'\)

所以
\[ G(x)=\sum_{i=1}^n\frac{-a_i}{1-a_ix} \]
所以
\[ f(x)=-xg(x)+n \]

\[ G(x)=\ln'(\prod_{i=1}^n (1-a_ix)) \]

然后上分治+NTT就可以在\(O(n\log^2n)\)的时间内解决了

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int MOD = 998244353;
const int G = 3;
const int invG = 332748118;
const int MAXN = 2000000;
int pow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)
            ans=(1LL*ans*a)%MOD;
        a=(1LL*a*a)%MOD;
        b>>=1;
    }
    return ans;
}
int rev[MAXN],inv_val[MAXN];
void cal_rev(int n,int lim){
    for(int i=0;i<n;i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(lim-1));
}
void cal_inv(int n){
    inv_val[0]=0;
    inv_val[1]=1;
    for(int i=2;i<=n;i++)
        inv_val[i]=(1LL*(MOD-MOD/i)*inv_val[MOD%i])%MOD;
}
void NTT(int *a,int opt,int n,int lim){
    for(int i=0;i<n;i++)
        if(i<rev[i])
            swap(a[i],a[rev[i]]);
    for(int i=2;i<=n;i<<=1){
        int len=i/2,tmp=pow((opt)?G:invG,(MOD-1)/i);
        for(int j=0;j<n;j+=i){
            int arr=1;
            for(int k=j;k<j+len;k++){
                int t=(1LL*a[k+len]*arr)%MOD;
                a[k+len]=(a[k]-t+MOD)%MOD;
                a[k]=(a[k]+t)%MOD;
                arr=(1LL*arr*tmp)%MOD;
            }
        }
    }
    if(!opt){
        int invN = pow(n,MOD-2);
        for(int i=0;i<n;i++)
            a[i]=(1LL*a[i]*invN)%MOD;
    }
}
void mul(int *a,int *b,int &at,int bt){
    int midlen=1,midlim=0;
    while((midlen)<(at+bt+2))
        midlen<<=1,midlim++;
    cal_rev(midlen,midlim);
    static int tmp[MAXN];
    for(int i=0;i<midlen;i++)
        tmp[i]=b[i];
    NTT(a,1,midlen,midlim);
    NTT(tmp,1,midlen,midlim);
    for(int i=0;i<midlen;i++)
        a[i]=(1LL*a[i]*tmp[i])%MOD;
    NTT(a,0,midlen,midlim);
    at+=bt;
    for(int i=0;i<=at;i++)
        tmp[i]=0;
    for(int i=at+1;i<midlen;i++)
        a[i]=0,tmp[i]=0;
}
void inv(int *a,int *b,int dep,int &midlen,int &midlim){
    if(dep==1){
        b[0]=pow(a[0],MOD-2);
        return;
    }
    inv(a,b,(dep+1)>>1,midlen,midlim);
    static int tmp[MAXN];
    while((dep<<1)>midlen)
        midlen<<=1,midlim++;
    for(int i=0;i<dep;i++)
        tmp[i]=a[i];
    for(int i=dep;i<midlen;i++)
        tmp[i]=0;
    cal_rev(midlen,midlim);
    NTT(tmp,1,midlen,midlim);
    NTT(b,1,midlen,midlim);
    for(int i=0;i<midlen;i++)
        b[i]=(1LL*b[i]*(2-1LL*tmp[i]*b[i]%MOD+MOD)%MOD)%MOD;
    NTT(b,0,midlen,midlim);
    for(int i=dep;i<midlen;i++)
        b[i]=0;
}
void qd(int *a,int &t){
    for(int i=0;i<t;i++)
        a[i]=1LL*a[i+1]*(i+1)%MOD;
    a[t]=0;
    t--;
}
void jf(int *a,int &t){
    t++;
    for(int i=t;i>0;i--){
        a[i]=1LL*a[i-1]*inv_val[i]%MOD;
    }
    a[0]=0;
}
void ln(int *a,int *b,int n){
    static int tmp[MAXN];
    for(int i=0;i<n;i++)
        tmp[i]=0,b[i]=a[i];
    int midlen=1,midlim=0;
    inv(a,tmp,n,midlen,midlim);
    int t=n;
    qd(b,t);
    mul(b,tmp,t,n);
    jf(b,t);
    for(int i=0;i<n;i++)
        tmp[i]=0;
    for(int i=n;i<midlen;i++)
        b[i]=tmp[i]=0;    
}
int n,a[MAXN],b[MAXN],c[MAXN];
int cnt=0,barrel[40][MAXN];
void solve(int l,int r,int *val,int &len){
    if(l==r){
        val[0]=1;
        val[1]=MOD-a[l];
        len=1;
        return;
    }
    int *la=barrel[cnt++],*ra=barrel[cnt++];
    int num=cnt,lenl,lenr;
    // printf("num=%lld\n",cnt);
    int mid=(l+r)>>1;
    solve(l,mid,la,lenl);
    solve(mid+1,r,ra,lenr);
    int midlen=1,midlim=0;
    while(midlen<(lenl+lenr+2))
        midlen<<=1,midlim++;
    cal_rev(midlen,midlim);
    NTT(la,1,midlen,midlim);
    NTT(ra,1,midlen,midlim);
    for(int i=0;i<midlen;i++)
        val[i]=(1LL*la[i]*ra[i])%MOD;
    NTT(val,0,midlen,midlim);
    for(int i=0;i<midlen;i++)
        la[i]=ra[i]=0;
    len=lenl+lenr;
    cnt=num-2;
}
signed main(){
    // freopen("test.in","r",stdin);
    // freopen("test.out","w",stdout);
    int T;
    scanf("%lld",&T);
    while(T--){
        // printf("ok %lld\n",T);
        scanf("%lld",&n);
        cal_inv(n+10);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        int len=0;
        solve(1,n,b,len);
        // for(int i=0;i<=n;i++)
        //     printf("%lld ",b[i]);
        // printf("\n");
        ln(b,c,n+1);
        // for(int i=0;i<=n;i++)
        //     printf("%lld ",c[i]);
        // printf("\n");
        int t=n;
        qd(c,t);
        for(int i=n;i>=1;i--)
            c[i]=MOD-c[i-1];
        c[0]=n;
        // for(int i=0;i<=n;i++)
        //     printf("%lld ",c[i]);
        // printf("\n");
        // for(int i=1;i<=n;i++)
        //     printf("%lld ",c[i]);
        // printf("\n");
        int ans=0;
        for(int i=1;i<=n;i++)
            ans^=c[i];
        printf("%lld\n",ans);
        for(int i=0;i<=n;i++)
            a[i]=b[i]=c[i]=0;
    }
    return 0;
}

转载于:https://www.cnblogs.com/dreagonm/p/10780281.html

内容概要:本文系统介绍了算术优化算法(AOA)的基本原理、核心思想及Python实现方法,并通过图像分割的实际案例展示了其应用价值。AOA是一种基于种群的元启发式算法,其核心思想来源于四则运算,利用乘除运算进行全局勘探,加减运算进行局部开发,通过数学优化器加速函数(MOA)和数学优化概率(MOP)动态控制搜索过程,在全局探索与局部开发之间实现平衡。文章详细解析了算法的初始化、勘探与开发阶段的更新策略,并提供了完整的Python代码实现,结合Rastrigin函数进行测试验证。进一步地,以Flask框架搭建前后端分离系统,将AOA应用于图像分割任务,展示了其在实际工程中的可行性与高效性。最后,通过收敛速度、寻优精度等指标评估算法性能,并提出自适应参数调整、模型优化和并行计算等改进策略。; 适合人群:具备一定Python编程基础和优化算法基础知识的高校学生、科研人员及工程技术人员,尤其适合从事人工智能、图像处理、智能优化等领域的从业者;; 使用场景及目标:①理解元启发式算法的设计思想与实现机制;②掌握AOA在函数优化、图像分割等实际问题中的建模与求解方法;③学习如何将优化算法集成到Web系统中实现工程化应用;④为算法性能评估与改进提供实践参考; 阅读建议:建议读者结合代码逐行调试,深入理解算法流程中MOA与MOP的作用机制,尝试在不同测试函数上运行算法以观察性能差异,并可进一步扩展图像分割模块,引入更复杂的预处理或后处理技术以提升分割效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值