题意:有一张顶点数为 的有向图。这张图的每个顶点由一个二元组 表示 。这张图不是简单图,对于任意两个顶点 ,如果 ,则从 到 一共有 条不同的边,如果 则没有边。白兔将在这张图上上演一支舞曲。白兔初始时位于该有向图的顶点 。白兔将会跳若干步。每一步,白兔会从当前顶点沿任意一条出边跳到下一个顶点。白兔可以在任意时候停止跳舞(也可以没有跳就直接结束)。当到达第一维为 的顶点就不得不停止,因为该顶点没有出边。假设白兔停止时,跳了 步,白兔会把这只舞曲给记录下来成为一个序列。序列的第 个元素为它第 步经过的边。问题来了:给定正整数 和 (),对于每个 (),求有多少种舞曲(假设其长度为 )满足 ,且白兔最后停在了坐标第二维为 的顶点?两支舞曲不同定义为它们的长度()不同或者存在某一步它们所走的边不同。输出的结果对 取模。
数据范围与约定:
对于全部数据, 为一个质数,,,,,,, 为 的约数,。
对于每组测试点,特殊限制如下:
- 测试点 :;
- 测试点 :, 的最大质因子为 ;
- 测试点 :, 的最大质因子为 ;
- 测试点 :;
- 测试点 :;
- 测试点 : 的最大质因子为 。
解析:一道很难的多项式题。
我们先考虑 的情况,这时候从任意一个点到另外一个点都有 条边,因此我们可以得到答案为:
其中 枚举的是白兔跳了多少步,每跳一步有 种方案,根据乘法原理方案为 ,由于跳了 步,故除起点外有 个经过的点,这 个点不确定,选择的方案有 种,故总方案数为 。
我们转化一下,可得:
其中出现了 这个式子,接下来就是关键的一步。
单位根反演
一个比较冷门的算法,它的主要形式为:
证明分为两种情况:
-
若 ,我们设 ,则:
-
-
若 ,根据等比数列求和公式,则:
-
它的主要应用是对于一个数列 ,求:
我们首先构造 的生成函数 ,那么:
证明如下:
同理,若我们要求:
我们把 平移 即可,即:
再用上面的式子即可求得所有 的 和。
了解单位根反演后,代入原式,得:
后面这个和式 可以继续用二项式定理化简,即:
发现 只与 有关,设为 ,代回原式:
接下来是一个神仙化简操作,利用如下恒等式:
代回原式:
其实现在就依稀可以看出后面那个和式是一个卷积形式,由于模数不一定要用 MTT 处理。为了更清楚地判断后面那个式子是不是卷积,我们继续化简。设 ,则:
我们把枚举 转为枚举 ,则:
然后经典套路,设 ,则:
这时候能很轻易地看出后面的和式即为卷积形式,由于 是变化的,且 ,所以 的下标范围恒为 , 的下标范围为 。故乘积后长度为 。直接 MTT 处理多项式乘法即可。注意单位根 需要预处理,因此需要先求 的原根。
的形式处理完后, 的形式就不难了,实际上就是把 的 换成输入的矩阵,同时改一下 的求法,先算出 ,其中 是初始状态矩阵,根据题意只有 处值为 , 则为单位矩阵,这里就要用到矩阵乘法。根据题意可得结束状态为 ,故 为上面这个式子算出的矩阵 处的值。
代码中将矩阵的横纵坐标都减去了 ,即从 开始。注意 MTT 要记得开 long double
,包括常量 。
/*
* @Author: clorf
* @Date: 2021-01-31 09:58:26
* @Last Modified by: clorf
* @Last Modified time: 2021-01-31 09:58:26
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<cctype>
#define INF 2e9
using namespace std;
const int maxn=140000;
const long double Pi=acos(-1.0);
const double eps=1e-7;
//1.数组开小
//2.没用long long/爆了类型存储范围
//3.写之前式子没推清楚
//4.变量写错(想当然typo/没想清楚含义)
//5.写之前没想清楚复杂度
//6.常量数字与long long连用时要加ll!!!
//7.考虑无解和多解的情况
//8.两个int连成爆long long的一定要加1ll!!!!
//9.先除后乘!!!!!!
template<class T>void read(T &x)
{
x=0;int f=0;char ch=getchar();
while(!isdigit(ch)){f|=(ch=='-');ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
int n,k,L,x,y,p;
int maxx=1,num,omega[maxn>>1];
inline int inc(int a,int b){return a+b>=p?a+b-p:a+b;}
namespace poly
{
int rev[maxn*3];
struct Cnum
{
long double x,y;
Cnum(long double p=0,long double q=0){x=p,y=q;}
Cnum conj(){return Cnum(x,-y);}
friend Cnum operator + (Cnum a,Cnum b){return Cnum(a.x+b.x,a.y+b.y);}
friend Cnum operator - (Cnum a,Cnum b){return Cnum(a.x-b.x,a.y-b.y);}
friend Cnum operator * (Cnum a,Cnum b){return Cnum(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
}a[maxn*3],b[maxn*3],c[maxn*3],d[maxn*3];
inline void ready(int len)
{
while(maxx<=len)
{
maxx<<=1;
num++;
}
for(int i=0;i<maxx;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(num-1));
}
inline void FFT(Cnum *a,int maxx,int type)
{
for(int i=0;i<maxx;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int mid=1;mid<maxx;mid<<=1)
{
Cnum w1(cos(Pi/mid),type*sin(Pi/mid));
for(int r=mid<<1,j=0;j<maxx;j+=r)
{
Cnum w(1,0);
for(int k=0;k<mid;k++,w=w*w1)
{
Cnum x=a[j|k];
Cnum y=a[j|k|mid]*w;
a[j|k]=x+y;
a[j|k|mid]=x-y;
}
}
}
if(!(~type))
for(int i=0;i<maxx;i++)
{
a[i].x/=maxx;
a[i].y/=maxx;
}
}
inline void MTT(int *f,int *g,int *h,int maxx,int p)
{
for(int i=0;i<maxx;i++)
{
a[i].x=f[i]>>15;
a[i].y=f[i]&32767;
c[i].x=g[i]>>15;
c[i].y=g[i]&32767;
}
FFT(a,maxx,1);
FFT(c,maxx,1);
for(int i=1;i<maxx;i++)
{
b[maxx-i]=a[i].conj();
d[maxx-i]=c[i].conj();
}
b[0]=a[0].conj();
d[0]=c[0].conj();
for(int i=0;i<maxx;i++)
{
Cnum A=(a[i]+b[i])*Cnum(0.5,0);
Cnum B=(a[i]-b[i])*Cnum(0,-0.5);
Cnum C=(c[i]+d[i])*Cnum(0.5,0);
Cnum D=(c[i]-d[i])*Cnum(0,-0.5);
a[i]=A*C+Cnum(0,1)*(A*D+B*C);
b[i]=B*D;
}
FFT(a,maxx,-1);
FFT(b,maxx,-1);
for(int i=0;i<maxx;i++)
{
int A=(long long)(a[i].x+0.5)%p;
int B=(long long)(a[i].y+0.5)%p;
int C=(long long)(b[i].x+0.5)%p;
h[i]=(1ll*A*(1<<30)%p+1ll*B*(1<<15)%p+C+p)%p;
}
}
}
int f[maxn*3],g[maxn*3],h[maxn*3];
struct matrix
{
int s[3][3];
matrix(){memset(s,0,sizeof(s));}
friend matrix operator + (matrix a,matrix b)
{
matrix c;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
c.s[i][j]=inc(a.s[i][j],b.s[i][j]);
return c;
}
friend matrix operator * (matrix a,int b)
{
matrix c;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
c.s[i][j]=1ll*a.s[i][j]*b%p;
return c;
}
friend matrix operator * (matrix a,matrix b)
{
matrix c;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
c.s[i][j]=inc(c.s[i][j],1ll*a.s[i][k]*b.s[k][j]%p);
return c;
}
}e,st,w;
inline int power(int a,int b,int p)
{
int ans=1;
for(;b;b>>=1)
{
if(b&1)
ans=1ll*ans*a%p;
a=1ll*a*a%p;
}
return ans;
}
inline matrix power(matrix a,int b)
{
matrix ans=e;
for(;b;b>>=1)
{
if(b&1)
ans=ans*a;
a=a*a;
}
return ans;
}
inline int getroot(int x)
{
static int fac[50],cnt=0;
int num=x-1;
for(int i=2;i<=x-1;i++)
{
if(num==1)
break;
if(!(num%i))
{
fac[++cnt]=i;
while(!(num%i))
num/=i;
}
}
for(int g=2;;g++)
{
bool flag=1;
for(int j=1;j<=cnt;j++)
if(power(g,(x-1)/fac[j],x)==1)
{
flag=0;
break;
}
if(flag)
return g;
}
}
int main()
{
scanf("%d%d%d%d%d%d",&n,&k,&L,&x,&y,&p);
x--,y--;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&w.s[i][j]);
e.s[0][0]=e.s[1][1]=e.s[2][2]=1;
st.s[0][x]=1;
omega[0]=1;
int G=getroot(p);
omega[1]=power(G,(p-1)/k,p);
for(int i=2;i<k;i++)
omega[i]=1ll*omega[i-1]*omega[1]%p;
int len=(k<<1)-2;
for(int i=0;i<=len;i++)
g[i]=omega[(k-1ll*i*(i-1)/2%k)%k];
for(int i=0;i<k;i++)
f[k-1-i]=1ll*omega[1ll*i*(i-1)/2%k]*(st*power(w*omega[i]+e,L)).s[0][y]%p;
len+=(k-1);
poly::ready(len);
poly::MTT(f,g,h,maxx,p);
int invk=power(k,p-2,p);
for(int i=0;i<k;i++)
printf("%lld\n",1ll*h[k-1+i]*invk%p*omega[1ll*i*(i-1)/2%k]%p);
return 0;
}