[数竞题(雾)][CodeChef]PARSIN/[JZOJ4704]Math

本文针对一组特定的三角函数求和问题进行了解析,并通过矩阵乘法快速幂的方法求解,最终给出了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

T组数据,每一组给定n,m,x,让你计算

k1+k2+...km=n(i=1msin(kix))(kiN)

1n109,m30,T10

题目分析

妈呀我搞的是OI不是IMO啊!

预备知识

首先你要会高中数学必修四的三角函数内容。
以下公式证明比较简单。我就不在此给出了,想要了解的可以自己去看书或查百度。

  • cos和角公式:
    • cos(αβ)=cos(α)cos(β)+sin(α)sin(β)
    • cos(α+β)=cos(α)cos(β)sin(α)sin(β)
  • sin和角公式:
    • sin(αβ)=sin(α)cos(β)cos(α)sin(β)
    • sin(α+β)=sin(α)cos(β)+cos(α)sin(β)
  • cos二倍角公式:cos(2α)=cos2(α)sin2(α)=cos2(α)(1cos2(α))=2cos2(α)1
  • sin二倍角公式:sin(2α)=2sin(α)cos(α)

推公式

有了这些东西,我们就可以愉快地推公式了。
令答案为f(n,m)
考虑当前km,如果km=1,那么其对答案贡献为

sin(x)i=1m1sin(kix)

sin(x)f(n1,m1)
如果km>1咧?
我们要推公式了,咳咳:
sin(kx)={sin((k1)x+x)=sin((k1)x)cos(x)+cos((k1)x)sin(x)sin((k2)x+2x)=sin((k2)x)cos(2x)+cos((k2)x)sin(2x)

两式相加:
2sin(kx)=sin((k1)x)cos(x)+cos((k1)x)sin(x)+sin((k2)x)cos(2x)+cos((k2)x)sin(2x)=sin((k1)x)cos(x)+cos((k1)x)sin(x)+sin((k2)x)(2cos2(x)1)+2cos((k2)x)sin(x)cos(x)=2cos((k2)x)sin(x)cos(x)+2sin((k2)x)cos2(x)sin((k2)x)+sin((k2)x+x)cos(x)+cos((k1)x)sin(x)=2cos((k2)x)sin(x)cos(x)+2sin((k2)x)cos2(x)sin((k2)x)+[sin((k2)x)cos(x)+cos((k2)x)sin(x)]cos(x)+cos((k1)x)sin(x)=3cos((k2)x)sin(x)cos(x)+3sin((k2)x)cos2(x)+cos((k1)x)sin(x)sin((k2)x)=3cos((k2)x)sin(x)cos(x)+3sin((k2)x)cos2(x)sin((k2)x)+[cos((k2)x)cos(x)sin((k2)x)sin(x)]sin(x)=4cos((k2)x)sin(x)cos(x)+3sin((k2)x)cos2(x)sin((k2)x)sin((k2)x)sin2(x)=4cos((k2)x)sin(x)cos(x)+3sin((k2)x)cos2(x)sin((k2)x)sin((k2)x)[1cos2(x)]=4cos((k2)x)sin(x)cos(x)+4sin((k2)x)cos2(x)2sin((k2)x)=4cos(x)[cos((k2)x)sin(x)+sin((k2)x)cos(x)]2sin((k2)x)=4cos(x)sin((k1)x)2sin((k2)x)

LATEX写到这里,我耗尽了所有的力气……
然后除以二得到sin(kx)=2cos(x)sin((k1)x)sin((k2)x)
然后我们发现这个和k1k2有关。
整理得到fn,m=sin(x)f(n1,m1)+2cos(x)f(n1,m)f(n2,m)。这个可能有点难理解,你展开一下就明白了。
有了这些,我们直接矩阵乘法快速幂就好了。
时间复杂度O(m3log2n)

代码实现

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;

const int M=35;
const int S=M<<1;

typedef double db;

struct matrix
{
    db num[S][S];
    int r,c;
}one,zero,mat;

matrix operator*(matrix a,matrix b)
{
    matrix c;
    c.r=a.r,c.c=b.c;
    for (int i=0;i<c.r;i++)
        for (int j=0;j<c.c;j++)
        {
            c.num[i][j]=0;
            for (int k=0;k<a.c;k++) c.num[i][j]+=a.num[i][k]*b.num[k][j];
        }
    return c;
}

matrix operator^(matrix a,int y)
{
    matrix ret=zero;
    for (;y;y>>=1,a=a*a) if (y&1) ret=ret*a;
    return ret;
}

db X,cosX,sinX,ans;
int T,n,m,s;

int main()
{
    freopen("math.in","r",stdin),freopen("math.out","w",stdout);
    for (scanf("%d",&T);T;T--)
    {
        scanf("%d%d%lf",&m,&n,&X);
        cosX=cos(X),sinX=sin(X),s=m+1<<1;
        memset(zero.num,0,sizeof zero.num),memset(one.num,0,sizeof one.num);
        zero.r=zero.c=one.r=one.c=s;
        for (int i=0;i<s;i++) zero.num[i][i]=1.0;
        for (int i=0;i<=m;i++) one.num[i][i+m+1]=1.0;
        for (int i=0;i<=m;i++)
        {
            one.num[i+m+1][i]=-1.0,one.num[i][i]=2*cosX;
            if (i) one.num[i-1][i]=sinX;
        }
        memset(mat.num,0,sizeof mat.num);
        mat.r=1,mat.c=s;
        mat.num[0][1]=sinX;
        mat=mat*(one^(n-1));
        ans=mat.num[0][m];
        if (ans>0) putchar('+');
        else putchar('-'),ans=-ans;
        while (ans>10) ans/=10.0;
        while (ans<1) ans*=10.0;
        printf("%d\n",(int)ans);
    }
    fclose(stdin),fclose(stdout);
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值