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

来源:互联网 发布:淘宝首页装修素材下载 编辑:程序博客网 时间:2024/06/04 20:08

题目大意

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)+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;}
1 0
原创粉丝点击