版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/86350559
题目:
简单地说,就是对于n的每一个长度为m的划分(
),求出其贡献的值之和。
分析:
非常神奇的三角函数题:
首先,可以想到,划分问题有一个很经典的DP
定义
表示将i划分为j个的方案数。
转移式为:
。即考虑划分状态中存在/不存在1的情况。存在1,则通过去掉那个1转移,不存在1,则通过每一位-1来转移。
考虑将这个DP方式套在这里:
定义
表示将n=i,m=j时的答案。
若m项中,存在1,则转移到
若不存在1,此时不必所有项都-1,只需要某一项-1就能转移了:
首先通过和角公式得到:
其中前半部分 就是我们要的,但后半部分还不对。
继续运用和角公式:
把
乘进去
因为
显然大括号里面的也是个和角公式。
综上所述:
换言之:
再加上之前的存在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));
}
}