【矩阵加速】【数学】2019雅礼集训 math

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/86350559

题目:

在这里插入图片描述
在这里插入图片描述
简单地说,就是对于n的每一个长度为m的划分( k i > 0 k_i>0 ),求出其贡献的值之和。


分析:

非常神奇的三角函数题:
首先,可以想到,划分问题有一个很经典的DP
定义 D P ( 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) 。即考虑划分状态中存在/不存在1的情况。存在1,则通过去掉那个1转移,不存在1,则通过每一位-1来转移。

考虑将这个DP方式套在这里:
定义 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)

若不存在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)

其中前半部分 s i n ( ( k i 1 ) x ) sin((k_i-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)\}
s i n ( 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)
因为 s i n 2 ( x ) = 1 c o s 2 ( x ) sin^2(x)=1-cos^2(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)
显然大括号里面的也是个和角公式。
= 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)
综上所述:
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)
换言之:
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)
再加上之前的存在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)
然后,这个就可以矩阵加速了。

#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));
	}
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/86350559