[BZOJ]3527 力(ZJOI2014)

  第一次背出FFT模板,在此mark一道裸题。

Description

  给出n个数qi,给出Fj的定义如下:

  

  令Ei=Fi/qi,求Ei。

Input

  第一行一个整数n。
  接下来n行每行输入一个数,第i行表示qi。

Output

  n行,第i行输出Ei。与标准答案误差不超过1e-2即可。

Sample Input

  5
  4006373.885184
  15375036.435759
  1717456.469144
  8514941.004912
  1410681.345880

Sample Output

  -16838672.693
  3439.793
  7509018.566
  4595686.886
  10903040.872

HINT

  n ≤ 100000,0 < qi < 1000000000。

 

Solution

  看到题目中 下标为j的项等于下标为i的项与下标为j±i的项的乘积之和,你应该会有所感觉吧。

  设,那么 

  显然两边都是卷积的式子,所以两边分别做一次FFT就可以了。

  然而我们再思考一下,发现两边的式子是可以合并的:

  设,那么 就完全成立了。只要做一次FFT就够了。

  时间复杂度O(nlogn)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define pi acos(-1)
#define MN 263005
using namespace std;
struct cp
{
    double v,i;
    friend cp operator+(const cp& a,const cp& b) {return (cp){a.v+b.v,a.i+b.i};}
    friend cp operator-(const cp& a,const cp& b) {return (cp){a.v-b.v,a.i-b.i};}
    friend cp operator*(const cp& a,const cp& b) {return (cp){a.v*b.v-a.i*b.i,a.v*b.i+a.i*b.v};}
}w[2][MN],A[MN],B[MN],C[MN];
double a[MN];
int r[MN];
int N,n;

void init(int n)
{
    register int i,j,k;
    for (N=1;N<=n;N<<=1); cp g=(cp){cos(pi*2/N),sin(pi*2/N)};
    for (i=j=0;i<N;r[++i]=j)
        for (k=N>>1;(j^=k)<k;k>>=1);
    w[0][0]=w[1][0]=(cp){1,0};
    for (i=1;i<N;++i) w[0][i]=w[0][i-1]*g;
    for (i=1;i<N;++i) w[1][i]=w[0][N-i];
}

void FFT(cp* a,bool g)
{
    register int i,j,k;
    for (i=1;i<N;++i) if (r[i]<i) swap(a[i],a[r[i]]);
    for (i=1;i<N;i<<=1)
        for (j=0;j<N;j+=(i<<1))
            for (k=0;k<i;++k)
            {
                cp x=a[i+j+k]*w[g][N/(i<<1)*k];
                a[i+j+k]=a[j+k]-x;
                a[j+k]=a[j+k]+x;
            }
    if (g) for (i=0;i<N;++i) a[i].v/=N,a[i].i/=N;
}

int main()
{
    register int i;
    scanf("%d",&n);
    for (i=1;i<=n;++i) scanf("%lf",&a[i]),A[i].v=a[i];
    for (i=1;i<n;++i)
        B[n+i].v=(double)1/i/i,B[n-i].v=(double)-1/i/i;
    init(n<<1);
    FFT(A,0); FFT(B,0);
    for (i=0;i<N;++i) C[i]=A[i]*B[i];
    FFT(C,1);
    for (i=1;i<=n;++i) printf("%.7lf\n",C[n+i].v);
}

 

Last Word

  推荐miskcoo的关于学习FFT的blog:从多项式乘法到快速傅里叶变换

转载于:https://www.cnblogs.com/ACMLCZH/p/8214047.html

内容概要:本文详细记录了对一个Android ARM64静态ELF文件中字符串加密机制的逆向分析过程。该ELF文件的所有字符串均被加密,无法通过常规strings命令或IDA直接识别。作者通过分析发现,加密字符串存储在.rodata段,其解密所需信息(包括密文地址、长度和16位密钥)保存在.data.rel.ro段的40字节描述符中。核心解密函数sub_10F408采用自反的双pass流密码算法,结合固定密钥KEY_TERM(由.data段24字节数据计算得出),实现字节级非线性、位置与长度相关的加密。文章还复现了完整的Python解密脚本,并揭示了该保护机制的本质为代码混淆而非强加密,最终成功批量解密全部956条字符串,暴露程序真实行为,如shell命令模板、设备标识篡改、网络重置等操作。此外,文中还提及未启用的自定义壳框架及其反dump设计。; 适合人群:具备逆向工程基础的安全研究人员、二进制分析人员及对ELF保护技术感兴趣的开发者。; 使用场景及目标:①学习ELF二进制中字符串加密的典型实现方式与逆向突破口;②掌握从结构识别、函数追踪到算法还原的完整逆向流程;③理解“绑定二进制”的完整性校验设计及其局限性;④实践编写IDAPython脚本自动化提取与解密敏感数据。; 阅读建议:此资源以实战案例驱动,不仅展示技术细节,更强调逆向思维与验证方法,建议读者结合IDA调试环境,逐步跟随文中步骤进行动态分析与算法验证,深入理解每一步的推理依据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值