题目描述
预备知识
DP
首先设F(N,M)表示M个数相加为N的答案。
F(N,M)=∑Mk=1F(N−K,M−1)∗sin(K∗X)
后面那个东西是什么?
推导
首先
sin(KX)=sin((K−1)X+X)=sin((K−1)X)cos(X)+cos((K−1)X)sin(X)
sin(KX)=sin((K−2)X+2X)=sin((K−2)X)cos(2X)+cos((K−2)X)sin(2X)
接下来把两式相加并除以2即可,相加结果
sin((K−1)X+X)=sin((K−1)X)cos(X)+cos((K−1)X)sin(X)+sin((K−2)X)cos(2X)+cos((K−2)X)sin(2X)
对括号内是2X的使用倍角公式,变成下式
2cos2(x)sin((K−2)X)+2sin(X)cos(X)cos((K−2)X)−sin((K−2)X)+cos(X)sin((K−1)X)+sin(X)cos((K−1)X)
把cos(X)sin((K−1)X)变成cos(X)[sin((K−2)X)cos(X)+cos((K−2)X)sin(X)]
代入并合并同类项
3cos2(X)sin((K−2)X)+3sin(X)cos(X)cos((K−2)X)+sin(X)cos((K−1)X)−sin((K−2)X)
把sin(X)cos((K−1)X)变成sin(X)[cos((K−2)X)cos(X)−sin((K−2)X)sin(X)]
代入并合并同类项
3cos2(X)sin((K−2)X)+4sin(X)cos(X)cos((K−2)X)−sin2(X)sin((K−2)X)−sin((K−2)X)
把sin2(X)sin((K−2)X)变成(1−cos2(X))sin((K−2)X)
代入并合并同类项
4cos(X)[cos(X)sin((K−2)X)+sin(X)cos((K−2)X)]−2sin((K−2)X)
注意到[]里的就是和角公式,等于sin((K−1)X)
然后得到结论
sin(KX)=2cos(X)sin((K−1)X)−sin((K−2)X)
回到DP,只要讨论K是否为1就可以优化DP式变成
F(N,M)=F(N-1,M-1)+2cos(X)F(N-1,M)-F(N-2,M)
然后矩阵乘法即可
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef double db;
const int maxm=30+10;
struct dong{
db a[65][65];
};
int s[30];
int i,j,k,l,t,n,m,ca;
db x,y,p;
dong a,b;
void mult(dong a,dong b,dong &c){
dong d;
int i,j,k;
fo(i,1,60)
fo(j,1,60)
d.a[i][j]=0;
fo(k,1,60)
fo(i,1,60)
if (a.a[i][k])
fo(j,1,60)
if (b.a[k][j])
d.a[i][j]=d.a[i][j]+a.a[i][k]*b.a[k][j];
fo(i,1,60)
fo(j,1,60)
c.a[i][j]=d.a[i][j];
}
int main(){
scanf("%d",&ca);
while (ca--){
scanf("%d%d",&m,&n);
scanf("%lf",&x);
fo(i,1,60)
fo(j,1,60)
a.a[i][j]=b.a[i][j]=0;
fo(i,31,60){
b.a[i][i-30]=1;
b.a[i][i]=2*cos(x);
}
fo(i,1,30) b.a[i][30+i]=-1;
fo(i,31,59) b.a[i][i+1]=sin(x);
a.a[1][1]=sin(x);
a.a[1][31]=sin(2*x);
a.a[1][32]=sin(x)*sin(x);
t=n-1;
while (t){
if (t%2) mult(a,b,a);
mult(b,b,b);
t/=2;
}
y=a.a[1][m];
if (y>0) printf("+");else printf("-");
y=fabs(y);
p=1;
if (y<1){
while (1){
if (y<p&&y>=p/10){
printf("%d\n",int(y/(p/10)));
break;
}
p/=10;
}
}
else{
while (1){
if (y>=p&&y<p*10){
printf("%d\n",int(y/p));
break;
}
p*=10;
}
}
}
}

本文介绍了一种利用三角恒等变换优化动态规划(DP)问题的方法,并通过矩阵乘法进一步加速计算过程。文章详细展示了如何通过递推公式简化问题,并给出了具体的C++实现代码。





