题目:
简单地说,就是对于n的每一个长度为m的划分(
k
i
>
0
k_i>0
ki>0),求出其贡献的值之和。
分析:
非常神奇的三角函数题:
首先,可以想到,划分问题有一个很经典的DP
定义
D
P
(
i
,
j
)
DP(i,j)
DP(i,j)表示将i划分为j个的方案数。
转移式为:
D
P
(
i
,
j
)
=
D
P
(
i
−
1
,
j
−
1
)
+
D
P
(
i
−
j
,
j
)
DP(i,j)=DP(i-1,j-1)+DP(i-j,j)
DP(i,j)=DP(i−1,j−1)+DP(i−j,j)。即考虑划分状态中存在/不存在1的情况。存在1,则通过去掉那个1转移,不存在1,则通过每一位-1来转移。
考虑将这个DP方式套在这里:
定义
f
(
i
,
j
)
f(i,j)
f(i,j)表示将n=i,m=j时的答案。
若m项中,存在1,则转移到
f
(
i
−
1
,
j
−
1
)
∗
s
i
n
(
x
)
f(i-1,j-1)*sin(x)
f(i−1,j−1)∗sin(x)
若不存在1,此时不必所有项都-1,只需要某一项-1就能转移了:
首先通过和角公式得到:
s
i
n
(
k
i
x
)
=
s
i
n
(
(
k
i
−
1
)
x
)
c
o
s
(
x
)
+
c
o
s
(
(
k
i
−
1
)
x
)
s
i
n
(
x
)
sin(k_ix)=sin((k_i-1)x)cos(x)+cos((k_i-1)x)sin(x)
sin(kix)=sin((ki−1)x)cos(x)+cos((ki−1)x)sin(x)
其中前半部分 s i n ( ( k i − 1 ) x ) sin((k_i-1)x) sin((ki−1)x)就是我们要的,但后半部分还不对。
继续运用和角公式:
s
i
n
(
x
)
c
o
s
(
(
k
i
−
1
)
x
)
=
s
i
n
(
x
)
{
c
o
s
(
(
k
i
−
2
)
x
)
c
o
s
(
x
)
−
s
i
n
(
(
k
i
−
2
)
x
)
s
i
n
(
x
)
}
sin(x)cos((k_i-1)x)=sin(x)\{cos((k_i-2)x)cos(x)-sin((k_i-2)x)sin(x)\}
sin(x)cos((ki−1)x)=sin(x){cos((ki−2)x)cos(x)−sin((ki−2)x)sin(x)}
把
s
i
n
(
x
)
sin(x)
sin(x)乘进去
=
s
i
n
(
x
)
c
o
s
(
x
)
c
o
s
(
(
k
i
−
2
)
x
)
−
s
i
n
2
(
x
)
s
i
n
(
(
k
i
−
2
)
x
)
=sin(x)cos(x)cos((k_i-2)x)-sin^2(x)sin((k_i-2)x)
=sin(x)cos(x)cos((ki−2)x)−sin2(x)sin((ki−2)x)
因为
s
i
n
2
(
x
)
=
1
−
c
o
s
2
(
x
)
sin^2(x)=1-cos^2(x)
sin2(x)=1−cos2(x)
=
c
o
s
(
x
)
{
s
i
n
(
x
)
c
o
s
(
(
k
i
−
2
)
x
)
+
c
o
s
(
x
)
s
i
n
(
(
k
i
−
2
)
x
)
}
−
s
i
n
(
(
k
i
−
2
)
x
)
=cos(x)\{sin(x)cos((k_i-2)x)+cos(x)sin((k_i-2)x)\}-sin((k_i-2)x)
=cos(x){sin(x)cos((ki−2)x)+cos(x)sin((ki−2)x)}−sin((ki−2)x)
显然大括号里面的也是个和角公式。
=
c
o
s
(
x
)
s
i
n
(
(
k
i
−
1
)
x
)
−
s
i
n
(
(
k
i
−
2
)
x
)
=cos(x)sin((k_i-1)x)-sin((k_i-2)x)
=cos(x)sin((ki−1)x)−sin((ki−2)x)
综上所述:
s
i
n
(
k
i
x
)
=
2
c
o
s
(
x
)
s
i
n
(
(
k
i
−
1
)
x
)
−
s
i
n
(
(
k
i
−
2
)
x
)
sin(k_ix)=2cos(x)sin((k_i-1)x)-sin((k_i-2)x)
sin(kix)=2cos(x)sin((ki−1)x)−sin((ki−2)x)
换言之:
f
(
i
,
j
)
=
2
c
o
s
(
x
)
f
(
i
−
1
,
j
)
−
f
(
i
−
2
,
j
)
f(i,j)=2cos(x)f(i-1,j)-f(i-2,j)
f(i,j)=2cos(x)f(i−1,j)−f(i−2,j)
再加上之前的存在1的情况。
就是
f
(
i
,
j
)
=
2
c
o
s
(
x
)
f
(
i
−
1
,
j
)
−
f
(
i
−
2
,
j
)
+
f
(
i
−
1
,
j
−
1
)
f(i,j)=2cos(x)f(i-1,j)-f(i-2,j)+f(i-1,j-1)
f(i,j)=2cos(x)f(i−1,j)−f(i−2,j)+f(i−1,j−1)
然后,这个就可以矩阵加速了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 100
using namespace std;
int n,m;
double tmp[MAXN][MAXN];
struct Matrix{
double a[MAXN][MAXN];
void operator *=(const Matrix & b) {
for(int i=0;i<3*m;i++)
for(int j=0;j<3*m;j++)
tmp[i][j]=0;
for(int i=0;i<3*m;i++)
for(int k=0;k<3*m;k++)
for(int j=0;j<3*m;j++)
tmp[i][j]+=a[i][k]*b.a[k][j];
for(int i=0;i<3*m;i++)
for(int j=0;j<3*m;j++)
a[i][j]=tmp[i][j];
}
}res,e;
void fsp(Matrix &x,int y){
while(y){
if(y&1)
res*=x;
x*=x;
y>>=1;
}
}
int t;
int main(){
SF("%d",&t);
while(t--){
double x;
SF("%d%d%lf",&m,&n,&x);
memset(res.a,0,sizeof res.a);
memset(e.a,0,sizeof e.a);
for(int i=0;i<m;i++){
e.a[i][i]=2.0*cos(x);
if(i!=m-1)
e.a[i+1][i]=sin(x);
e.a[i+m][i]=-1;
}
for(int i=m;i<2*m;i++)
e.a[i-m][i]=1;
res.a[0][m-1]=sin(x);
// for(int i=1;i<n;i++){
// res*=e;
// for(int j=0;j<2*m;j++)
// PF("%lf ",res.a[0][j]);
// PF("\n");
// }
fsp(e,n-1);
double ans=res.a[0][0];
// PF("[%lf]",ans);
if(ans<0){
PF("-");
ans=-ans;
}
else
PF("+");
while(ans>=10.0)
ans/=10.0;
while(ans*10.0<10.0)
ans*=10.0;
PF("%d\n",int(ans));
}
}