[hdu5307] He is Flying [FFT+数学推导]

本文详细解析了如何利用FFT快速傅立叶变换解决区间和问题,通过对前缀和的巧妙运用,结合数学推导,实现了高效求解所有长度为s的区间的愉悦值总和。

题面

传送门

思路

看到这道题,我的第一想法是前缀和瞎搞,说不定能$O\left(n\right)$?

事实证明我的确是瞎扯......

题目中的提示

这道题的数据中告诉了我们:

$sum\left(s\left[i\right]\right)<=50000$

也就是说,总长度是很小的,这提示我们往“通过长度来解题”的方向上想

那么,最便捷的处理区间长度和的算法是什么呢?前缀和

我们需要求什么?

做题的过程中,一定不能忘记这一点:我们要求的是,所有长度为s的区间的愉悦值总和

那么,一个长度为s的区间,在关于长度的前缀和pre中是怎么表示的呢?

就是所有的$pre[i]-pre[i-s]$,也就是它们下标之差是一定的

下标差一定......不同的决策之和......

FFT卷积!

FFT

我们考虑一个前缀和数组$pre$,范围从$0$到$sum(s[i])$,将它反向成为$antipre$,那么有:

$pre[i]=antipre[n-i+1]$

显然,当我们把$pre[i]$作为一个多项式$A$的$x^{i+1}$项的系数,把$antipre[i]$作为另一个多项式$B$的$x^{i+1}$项的系数时,将两个多项式乘起来,那么得到的新多项式$C$的第$x^{i+2}$项的系数,就保存了关于所有长度为i+1的区间的信息

保存什么信息?

题目中描述了,可能有区间的长度为0,也就是说,前缀和中的同一个长度数值上可能有多个点

我们设前缀和长度为s的一共有$tot[s]$个点,最左边的是$l[s]$,最右边的是$r[s]$

那么对于一段长度为s的,我们的信息来自于$pre[i]$和$pre[i-s]$

假设我们当前要求rr-s这个长度和rr这个长度的信息,那么我们来考虑一下它们总共的贡献值是多少

o_%e6%97%a0%e6%a0%87%e9%a2%98.png

$l1,r1$就是$l[rr-s]$和$r[rr-s]$,$l2,r2$同理

那么总的愉悦值贡献$contribution$应该是这样的:

$contribution=\sum_{i=l1}^{r1}\sum_{j=l2}^{r2}\left(j-i+1\right)$

$contribution=pq+\sum_{j=l2}^{r2}jp-\sum_{i=l1}^{r1}iq$

$contribution=pq+\frac{pq\left(r2+l2\right)}2-\frac{qp\left(l1+r1\right)}2$

$contribution=\frac 12pq\left(l2-l1+r2-r1+2\right)$

因为前缀和求区间$[l,r]$是减掉第l-1项的,所以上式中的$pq$项抵消掉了

因此

$contribution=\frac 12pq\left(l2-l1+r2-r1\right)$

这个东西显然可以两次FFT相减来处理

总结

本题到了这里就结束了

纵观整个过程,我们从题目要求的东西,想到使用前缀和,又从需要对前缀和处理什么得到使用FFT的方法,最后用数学推导得到了FFT的方法

换句话说,整个解题过程中我们的每一步操作都是有迹可循、有原因的,不是因为“我见过这种题所以用FFT”——总会有你没见过的题出现

解题的过程、建模的过程是一个不断修正矛盾(问题)的过程,这个矛盾既可以是时间矛盾、正确性矛盾,也可以是代码编写复杂度的矛盾,但是核心的一点就是:矛盾的修正要有方向性、有依据

一定是因为这里不对了我才去优化,而不是一上来就瞎猜一个高级方法然后硬想,那样想破了脑袋都想不出来

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
inline ll read(){
    ll re=0,flag=1;char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') re=(re<<1ll)+(re<<3ll)+ch-'0',ch=getchar();
    return re*flag;
}
struct complex{
    long double x,y;
    complex(long double xx=0,long double yy=0){x=xx;y=yy;}
    complex operator +(const complex &b){return complex(x+b.x,y+b.y);}
    complex operator -(const complex &b){return complex(x-b.x,y-b.y);}
    complex operator *(const complex &b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);}
}A[300010],B[300010];
const long double pi=acos(-1.0);
ll n,m,limit=1,cnt=0,r[300010];
void fft(complex *a,long double type){
    ll i,j,k,mid;complex x,y,wn,w;
    for(i=0;i<limit;i++) if(i<r[i]) swap(a[i],a[r[i]]);
    for(mid=1;mid<limit;mid<<=1ll){
        wn=complex(cos(pi/mid),type*sin(pi/mid));
        for(j=0;j<limit;j+=(mid<<1ll)){
            w=complex(1,0);
            for(k=0;k<mid;k++,w=w*wn){
                x=a[j+k];y=a[j+k+mid]*w;
                a[j+k]=x+y;a[j+k+mid]=x-y;
            }
        }
    }
    if(type==-1) for(i=0;i<=limit;i++) a[i].x=(ll)(a[i].x/limit+0.1); 
}
ll tot[50010],s[100010],L[100010],R[100010];
ll ans[100010];
int main(){
    ll T=read(),i,j,sum,tmp;
    while(T--){
        n=read();sum=0;memset(ans,0,sizeof(ans));memset(tot,0,sizeof(tot));tot[0]=1;
        memset(L,127,sizeof(L));memset(R,0,sizeof(R));L[0]=0;memset(s,0,sizeof(s));
        for(i=1;i<=n;i++){
            s[i]=read(),tot[sum+=s[i]]++;
            L[sum]=min(L[sum],i);R[sum]=max(R[sum],i);
        }
        tmp=0;
        for(i=1;i<=n;i++){
            if(s[i]) tmp=0;
            else tmp++,ans[0]+=(ll)(tmp*(tmp+1)/2ll);
        }//0要特殊处理,我们的算法并不能得到零的解,这一点具体是为什么,可以自己推导一下,会发现最后所有0的项的解都自我抵消掉了
        
        memset(r,0,sizeof(r));
        while(limit<=(sum<<1)) limit<<=1,cnt++;
        for(i=0;i<limit;i++) r[i]=((r[i>>1]>>1)|((i&1)<<(cnt-1)));
        
        memset(A,0,sizeof(A));memset(B,0,sizeof(B));
        for(i=0;i<=sum;i++) A[i+1].x=tot[i]*(L[i]+R[i])/2.0,B[i+1].x=tot[sum-i];//减去l1r1
        fft(A,1);fft(B,1);
        for(i=0;i<=limit;i++) A[i]=A[i]*B[i];
        fft(A,-1);
        for(i=1;i<=sum;i++) ans[i]-=(ll)A[sum+2-i].x;
        
        memset(A,0,sizeof(A));memset(B,0,sizeof(B));
        for(i=0;i<=sum;i++) A[i+1].x=tot[i],B[i+1].x=tot[sum-i]*(L[sum-i]+R[sum-i])/2.0;//加上r2l2
        fft(A,1);fft(B,1);
        for(i=0;i<=limit;i++) A[i]=A[i]*B[i];
        fft(A,-1);
        for(i=1;i<=sum;i++) ans[i]+=(ll)A[sum+2-i].x;
        
        //整个过程中,因为我们分析的公式是针对区间[l,r]的l和r的,但是算法实现的时候是针对l-1和r的(前缀和思想),所以原式中要去掉那个p*q
        
        for(i=0;i<=sum;i++) printf("%lld\n",ans[i]);
    }
}

转载于:https://www.cnblogs.com/dedicatus545/p/8846564.html

代码下载地址: https://pan.quark.cn/s/a4b39357ea24 在计算机视觉技术中,数据集扮演着训练和评估模型的核心角色。Labelme作为一个广受欢迎的开源工具,能够支持用户以交互方式对图像进行标注,而COCO(Common Objects in Context)则是一种被广泛采纳的数据集标准格式,适用于包括物体检测、图像分割在内的多种任务。本文将详细阐述如何将Labelme生成的标注数据转换为COCO数据集的标准格式。 Labelme标注的图像在输出为JSON格式时,会包含以下核心内容: 1. `version`: 指明JSON文件的版本信息。 2. `flags`: 目前未定义或保持为空,预留用于未来的功能扩展。 3. `shapes`: 列表形式存储对象的形状信息,每个形状项包含`label`(对象类别名称),`points`(构成对象边缘的多边形顶点),以及`shape_type`(通常为“polygon”)。 4. `imagePath`和`imageData`: 提供原始图像的存储路径和二进制数据,便于后续图像的还原。 5. `imageHeight`和`imageWidth`: 明确标注图像的垂直和水平尺寸。 COCO数据集的标准格式中定义了三种主要的标注类型: 1. Object instances(目标实例):主要用于执行物体检测任务。 2. Object keypoints(目标上的关键点):适用于人体姿态估计相关应用。 3. Image captions(看图说话):用于生成图像的文本描述。 COCO的JSON结构中包含以下基本组成部分: 1. `images`:记录图像的基本属性,包括`height`(高度)、`...
内容概要:本文围绕基于Basisformer模型的时间序列锂离子电池SOC(State of Charge,荷电状态)预测展开研究,利用PyTorch深度学习框架构建并训练模型,旨在提升锂电池SOC估计的准确性与鲁棒性。该方法融合Transformer架构的核心机制,通过引入基函数(Basis)分解策略,有效捕捉电池充放电过程中长时序、非线性动态特征,增强模型对复杂工况的适应能力。研究不仅详细阐述了Basisformer的网络结构设计、注意力机制优化与训练流程,还提供了完整的Python代码实现方案,涵盖数据预处理、模型搭建、损失函数定义、训练验证及结果可视化等环节,便于科研人员快速复现、调优并拓展至其他电池状态预测任务。; 适合人群:具备一定深度学习与Python编程基础,熟悉PyTorch框架,从事电池管理系统(BMS)、新能源汽车、储能系统、智能传感等领域的高校研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于动力电池与储能系统的实时SOC估算模块,提升系统安全性与能量利用效率;②作为学术研究的基础模型,用于复现、改进基于Transformer的时间序列预测方法在电化学系统中的应用;③为数据驱动的电池健康状态(SOH)、剩余使用寿命(RUL)联合估计提供可扩展的技术框架。; 阅读建议:建议读者结合所提供的代码与公开电池数据集(如NASA、CALCE等)进行动手实践,深入理解模型的输入输出结构与时序建模逻辑,同时可尝试引入温度、老化周期等多维特征,或融合物理模型构建混合预测架构,以进一步提升预测精度与泛化能力。
内容概要:本文系统阐述了基于动态规划算法优化插电式混合动力电动汽车(PHEV)能源管理的技术方案,结合Matlab与Simulink工具实现完整的仿真建模与代码开发。通过动态规划这一全局优化方法,在已知驾驶循环条件下,精确求解发动机、电机及电池之间的最优能量分配策略,以实现燃油消耗与排放的最小化目标,解决PHEV多能源路径规划中的复杂决策问题。文中提供了详尽的仿真模型构建流程与算法实现步骤,涵盖车辆动力学建模、能量管理架构设计、状态空间定义、代价函数构造、最优控制律求解及结果可视化分析等关键环节,全面揭示PHEV能量管理系统的内在机制与优化逻辑。; 适合人群:具备一定Matlab/Simulink编程基础,从事新能源汽车、智能控制、电力电子、自动化或交通运输工程等相关领域的研究生、科研人员及工程技术人员,尤其适合专注于车辆能量管理策略、节能控制算法研究的专业人士。; 使用场景及目标:①深入掌握动态规划在混合动力汽车能量管理中的理论基础与工程实现方法;②学习如何在Matlab/Simulink环境中搭建PHEV整车仿真平台并实施多目标优化仿真;③为学术研究、学位论文撰写或实际工程项目提供可复用的算法框架、模型模板与技术支持,支撑后续对等效燃油消耗最小化策略(ECMS)、模型预测控制(MPC)、实时优化算法等的对比研究与性能评估。; 阅读建议:建议读者结合所提供的完整代码与Simulink模型文件,逐模块调试运行,重点理解状态变量离散化处理、前后向递推求解过程、惩罚项设置以及边界条件处理等核心技术细节,同时可进一步拓展应用于不同工况场景、不同车型结构或与其他优化算法(如庞特里亚金极小值原理PMP)的对比验证,从而深化对PHEV能量管理实时性与全局性平衡问题的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值