[JZOJ5726] 入门多项式题
Posted ZLTJohn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JZOJ5726] 入门多项式题相关的知识,希望对你有一定的参考价值。
题目描述
解题思路
完全不会线代的菜鸡肯定是用猎奇解法了。
当然还是得知道特征多项式是啥玩意。
特征多项式
对于一个矩阵
A
A
,他的特征多项式,其中I为单位矩阵,x可以是矩阵或者一个数。大概长这样
f(x)=c0A0+c1A1...cnAn
f
(
x
)
=
c
0
A
0
+
c
1
A
1
.
.
.
c
n
A
n
,其中A的乘法为矩阵乘法。
注意到
f(A)=0
f
(
A
)
=
0
,那么这肯定是题目的可行解。
怎么解出这个多项式?随便带些x值进去插值。
知道这个,我们就知道一定存在次数在n以内的解。最优解不比特征多项式劣。
我们考虑枚举答案次数m,然后此时我们要确定系数数组,由于
Ai
A
i
是可以知道的,那么就变成了
n2
n
2
个线性方程组,可以高斯消元。时间复杂度
O(n5)
O
(
n
5
)
。
我们是怎么判断可行的呢?先令c[m]=1,一种暴力判法是先用一部分方程解出c[],然后再代进剩下方程里看看对不对,但这样很麻烦。需要新思路。
假如我们已经求出最优解,那么系数数组应该是 c0...cm,cm=1,m≤n c 0 . . . c m , c m = 1 , m ≤ n 。注意到,我们对c数组随便乘一个系数,它依然是一个可行解, cm=1 c m = 1 是题目限制得来的。我们考虑把这个限制先取消掉,那么可以发现, cm c m 可以等于任何数,也就是说,他是一个自由元。
发现这个,我们就可以先假定m=n,然后开始高斯消元,一旦消到自由元,那么此时我们已经得到了最优的答案次数k。此时令 ck=1 c k = 1 ,次数更高的系数我们令他全是0即可。再对前面的方程回代即可。
时间 O(n4) O ( n 4 )
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
//开 O2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
typedef long long ll;
typedef long long LL;
typedef double db;
const int N=70+5;
int a[N][N][N],b[N*N][N],c[N],i,j,k,l,tb,n,mo,xs;
int ksm(int x,int y)
int ret=1;
while (y)
if (y&1) ret=1ll*ret*x%mo;
y>>=1;
x=1ll*x*x%mo;
return ret;
int main()
freopen("poly.in","r",stdin);
//freopen("poly.out","w",stdout);
scanf("%d %d",&n,&mo);
fo(i,1,n)
fo(j,1,n)
scanf("%d",a[1][i]+j);
fo(i,1,n) a[0][i][i]=1;
fo(l,2,n)
fo(i,1,n)
fo(k,1,n)
fo(j,1,n)
a[l][i][j]=(a[l][i][j]+1ll*a[1][i][k]*a[l-1][k][j])%mo;
fo(i,1,n)
fo(j,1,n)
fo(k,0,n) b[tb][k]=a[k][i][j];
tb++;
fo(i,0,n)
fo(j,i,n*n) if (b[j][i]) break;
if (j>n*n) break;
fo(k,i,n) swap(b[i][k],b[j][k]);
xs=ksm(b[i][i],mo-2);
fo(k,i,n) b[i][k]=1ll*b[i][k]*xs%mo;
fo(j,i+1,n*n)
xs=b[j][i];
fo(k,i,n) b[j][k]=(b[j][k]-1ll*b[i][k]*xs)%mo;
n=i;
c[n]=1;
fd(i,n-1,0)
c[i]=0;
fo(j,i+1,n)
c[i]=(c[i]-1ll*b[i][j]*c[j])%mo;
c[i]=1ll*c[i]*ksm(b[i][i],mo-2)%mo;
if (c[i]<0) c[i]+=mo;
printf("%d\\n",n);
fo(i,0,n) printf("%d ",c[i]);
以上是关于[JZOJ5726] 入门多项式题的主要内容,如果未能解决你的问题,请参考以下文章