[数学记录]P5293 [HNOI2019]白兔之舞
command_block · · 个人记录
题意 : 有一个
给出权值数组
如果有
定义一支舞曲为从给定点
给定整数
答案对给定的质数
设
注意我们的行走方式允许随意跳过某些行,这不便于DP,我们考虑把行压紧。
设
容易得知如下DP :
可以把转移写成矩阵的形式,设向量
易得边界为
求得
使用单位根反演。
使用
发现是个二项式定理 (
对于后面的
前面的求和其实就是任意长度的
尝试使用
考虑
具体来讲,如果需要计算
能够发现就是差卷积。注意上界。
任意模数卷积需要MTT,求单位根需要原根。
复杂度
个人觉得是一道不错的练习题,可是赛场上逼着选手写MTT有点毒瘤。
#include<algorithm>
#include<cstdio>
#include<cmath>
#define ld double
#define ll long long
#define Maxn 135000
using namespace std;
int mod;
ll powM(ll a,int t=mod-2){
ll ret=1;
while(t){
if (t&1)ret=ret*a%mod;
a=a*a%mod;t>>=1;
}return ret;
}
namespace Grt
{
int gcd(int a,int b)
{return !b ? a : gcd(b,a%b);}
int getphi(int n){
int ret=n,p=2;
while(p*p<=n){
if (n%p==0){
while(n%p==0)n/=p;
ret=ret/p*(p-1);
}p++;
}if (n>1)ret=ret/n*(n-1);
return ret;
}
int d[25],tn;
void getft(int n){
int sav=n,p=2;
while(p*p<=n){
if (n%p==0){
while(n%p==0)n/=p;
d[++tn]=sav/p;
}p++;
}if (n>1)d[++tn]=sav/n;
}
bool check(int n){
for (int i=1;i<=tn;i++)
if (powM(n,d[i])==1)
return 0;
return 1;
}
int get(){
getft(getphi(mod));
for (int i=1;;i++)
if (gcd(i,mod)==1&&check(i))
return i;
}
}
const ld Pi=acos(-1);
struct CP{
ld x,y;
CP operator + (const CP& B) const
{return (CP){x+B.x,y+B.y};}
CP operator - (const CP& B) const
{return (CP){x-B.x,y-B.y};}
CP operator * (const CP& B) const
{return (CP){x*B.x-y*B.y,x*B.y+y*B.x};}
};
int tr[Maxn<<1];
void FFT(CP *f,int op,int n)
{
static CP w[Maxn]={(CP){1.0,0.0}};
for (int i=0;i<n;i++)
if (i<tr[i])swap(f[i],f[tr[i]]);
for(int l=1;l<n;l<<=1){
CP tG=(CP){cos(Pi/l),sin(Pi/l)*op};
for (int i=l-2;i>=0;i-=2)w[i+1]=(w[i]=w[i>>1])*tG;
for(int k=0;k<n;k+=l+l)
for(int p=0;p<l;p++){
CP sav=w[p]*f[k|l|p];
f[k|l|p]=f[k|p]-sav;
f[k|p]=f[k|p]+sav;
}
}
}
void times(int *f,int *g,int n,int lim)
{
static CP P1[Maxn<<1],P2[Maxn<<1],Q[Maxn<<1];
for (int i=0,sav;i<lim;i++){
P1[i]=(CP){f[i]>>15,f[i]&32767};
P2[i]=(CP){f[i]>>15,-(f[i]&32767)};
Q[i]=(CP){g[i]>>15,g[i]&32767};
}for (int i=1;i<n;i++)
tr[i]=tr[i>>1]>>1|((i&1)?n>>1:0);
FFT(P1,1,n);FFT(P2,1,n);FFT(Q,1,n);
for (int i=0;i<n;i++){
Q[i].x/=n;Q[i].y/=n;
P1[i]=P1[i]*Q[i];
P2[i]=P2[i]*Q[i];
}FFT(P1,-1,n);FFT(P2,-1,n);
for (int i=0;i<lim;i++){
ll a1b1=0,a1b2=0,a2b1=0,a2b2;
a1b1=(ll)floor((P1[i].x+P2[i].x)/2+0.4)%mod;
a1b2=(ll)floor((P1[i].y+P2[i].y)/2+0.4)%mod;
a2b1=((ll)floor(P1[i].y+0.4)-a1b2)%mod;
a2b2=((ll)floor(P2[i].x+0.4)-a1b1)%mod;
f[i]=((((a1b1<<15)+(a1b2+a2b1))<<15)+a2b2)%mod;
if (f[i]<0)f[i]+=mod;
}
}
int n;
struct Mat
{
int w[3][3];
void clr(){
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
w[i][j]=0;
}
Mat operator * (const Mat &B) const{
Mat R;R.clr();
for (int k=0;k<n;k++)
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
R.w[i][j]=(R.w[i][j]+1ll*w[i][k]*B.w[k][j])%mod;
return R;
}
Mat operator * (const int &x) const{
Mat R;R.clr();
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
R.w[i][j]=1ll*w[i][j]*x%mod;
return R;
}
Mat operator + (const Mat &B) const{
Mat R;
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
R.w[i][j]=(w[i][j]+B.w[i][j])%mod;
return R;
}
}T,I;
Mat powM(Mat a,int t=mod-2){
Mat ret=I;
while(t){
if (t&1)ret=ret*a;
a=a*a;t>>=1;
}return ret;
}
int G,k,L,x,y,f[Maxn<<1],g[Maxn<<1],c[Maxn],pw[Maxn];
int main()
{
scanf("%d%d%d%d%d%d",&n,&k,&L,&x,&y,&mod);
x--;y--;
G=powM(Grt::get(),(mod-1)/k);
for (int i=0;i<n;i++)I.w[i][i]=1;
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
scanf("%d",&T.w[i][j]);
pw[0]=1;
for (int i=1;i<=k;i++)pw[i]=1ll*pw[i-1]*G%mod;
for (int i=0;i<k+k;i++){
c[i]=1ll*i*(i-1)/2%k;
g[i]=pw[k-c[i]];
}for (int i=0;i<k;i++)
f[i]=1ll*powM(T*powM(G,i)+I,L).w[x][y]*pw[c[i]]%mod;
int len=1;while(len<4*k)len<<=1;
reverse(g,g+k+k);times(f,g,len,k+k);reverse(f,f+k+k);
int invk=powM(k);
for (int i=0;i<k;i++)
printf("%d\n",1ll*f[i]*pw[c[i]]%mod*invk%mod);
return 0;
}