题目大意
有T组数据,每一组给定
∑k1+k2+...km=n(∏i=1msin(kix))(ki∈N)
1≤n≤109,m≤30,T≤10
题目分析
妈呀我搞的是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(α)−(1−cos2(α))=2cos2(α)−1
- sin二倍角公式:sin(2α)=2sin(α)cos(α)
推公式
有了这些东西,我们就可以愉快地推公式了。
令答案为f(n,m)。
考虑当前km,如果km=1,那么其对答案贡献为
sin(x)∏i=1m−1sin(kix)
即sin(x)f(n−1,m−1)。
如果km>1咧?
我们要推公式了,咳咳:
sin(kx)={sin((k−1)x+x)=sin((k−1)x)cos(x)+cos((k−1)x)sin(x)sin((k−2)x+2x)=sin((k−2)x)cos(2x)+cos((k−2)x)sin(2x)
两式相加:
2sin(kx)=sin((k−1)x)cos(x)+cos((k−1)x)sin(x)+sin((k−2)x)cos(2x)+cos((k−2)x)sin(2x)=sin((k−1)x)cos(x)+cos((k−1)x)sin(x)+sin((k−2)x)(2cos2(x)−1)+2cos((k−2)x)sin(x)cos(x)=2cos((k−2)x)sin(x)cos(x)+2sin((k−2)x)cos2(x)−sin((k−2)x)+sin((k−2)x+x)cos(x)+cos((k−1)x)sin(x)=2cos((k−2)x)sin(x)cos(x)+2sin((k−2)x)cos2(x)−sin((k−2)x)+[sin((k−2)x)cos(x)+cos((k−2)x)sin(x)]cos(x)+cos((k−1)x)sin(x)=3cos((k−2)x)sin(x)cos(x)+3sin((k−2)x)cos2(x)+cos((k−1)x)sin(x)−sin((k−2)x)=3cos((k−2)x)sin(x)cos(x)+3sin((k−2)x)cos2(x)−sin((k−2)x)+[cos((k−2)x)cos(x)−sin((k−2)x)sin(x)]sin(x)=4cos((k−2)x)sin(x)cos(x)+3sin((k−2)x)cos2(x)−sin((k−2)x)−sin((k−2)x)sin2(x)=4cos((k−2)x)sin(x)cos(x)+3sin((k−2)x)cos2(x)−sin((k−2)x)−sin((k−2)x)[1−cos2(x)]=4cos((k−2)x)sin(x)cos(x)+4sin((k−2)x)cos2(x)−2sin((k−2)x)=4cos(x)[cos((k−2)x)sin(x)+sin((k−2)x)cos(x)]−2sin((k−2)x)=4cos(x)sin((k−1)x)−2sin((k−2)x)
然后除以二得到sin(kx)=2cos(x)sin((k−1)x)−sin((k−2)x)。
然后我们发现这个和k−1,k−2有关。
整理得到fn,m=sin(x)f(n−1,m−1)+2cos(x)f(n−1,m)−f(n−2,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;
}