Loj 3058. 「HNOI2019」白兔之舞
Loj 3058. 「HNOI2019」白兔之舞
题目描述
有一张顶点数为 \((L+1)\times n\) 的有向图。这张图的每个顶点由一个二元组 \((u,v)\) 表示 \((0\le u\le L,1\le v\le n)\)。这张图不是简单图,对于任意两个顶点 \((u_1,v_1),(u_2,v_2)\),如果 \(u_1<u_2\),则从 \((u_1,v_1)\) 到 \((u_2,v_2)\) 一共有 \(w(v_1,v_2)\) 条不同的边,如果 \(u_1\ge u_2\) 则没有边。
白兔将在这张图上上演一支舞曲。白兔初始时位于该有向图的顶点 \((0,x)\)。
白兔将会跳若干步。每一步,白兔会从当前顶点沿任意一条出边跳到下一个顶点。白兔可以在任意时候停止跳舞(也可以没有跳就直接结束)。当到达第一维为 \(L\) 的顶点就不得不停止,因为该顶点没有出边。
假设白兔停止时,跳了 \(m\) 步,白兔会把这只舞曲给记录下来成为一个序列。序列的第 \(i\) 个元素为它第 \(i\) 步经过的边。
问题来了:给定正整数 \(k\) 和 \(y\ (1\le y\le n)\),对于每个 \(t\ (0\le t<k)\),求有多少种舞曲(假设其长度为 \(m\))满足 \(m \bmod k=t\),且白兔最后停在了坐标第二维为 \(y\) 的顶点?
两支舞曲不同定义为它们的长度(\(m\))不同或者存在某一步它们所走的边不同。
输出的结果对 \(p\) 取模。
输入格式
第一行六个用空格隔开的整数 \(n,k,L,x,y,p\)。
接下来 \(n\) 行,每行有 \(n\) 个用空格隔开的整数,第 \(i\) 行的第 \(j\) 个数表示 \(w(i,j)\)。
输出格式
依次输出 \(k\) 行,每行一个数表示答案对 \(p\) 取模的结果。
样例
样例输入 1
2 2 3 1 1 998244353
2 1
1 0
样例输出 1
16
18
样例输入 2
3 4 100 1 3 998244353
1 1 1
1 1 1
1 1 1
样例输出 2
506551216
528858062
469849094
818871911
数据范围与提示
对于全部数据,\(p\) 为一个质数,\(10^8<p<2^{30}\),\(1\le n\le 3\),\(1\le x\le n\),\(1\le y\le n\),\(0\le w(i,j)<p\),\(1\le k\le 65536\),\(k\) 为 \(p-1\) 的约数,\(1\le L\le 10^8\)。
对于每组测试点,特殊限制如下:
- 测试点 \(1,2\):\(L\le 10^5\);
- 测试点 \(3\):\(n=1,w(1,1)=1\),\(k\) 的最大质因子为 \(2\);
- 测试点 \(4\):\(n=1\),\(k\) 的最大质因子为 \(2\);
- 测试点 \(5\):\(n=1,w(1,1)=1\);
- 测试点 \(6\):\(n=1\);
- 测试点 \(7,8\):\(k\) 的最大质因子为 \(2\)。
\(\\\)
湖南的题好神啊,只能\(Orz\)了。
先考虑从\(x\)走\(L\)步到\(y\),假设每次向右只走一格的方案数。很容易写出一个\(DP\)方程,然后用矩阵快速幂优化。我们读进来的矩阵\(A\)就是转移矩阵。所以方案数就是\([A^i]_{x,y}\)。
计算答案的时候就枚举走了\(i\)步:
=\sum_{i=0}^L\frac{1}{k}\sum_{j=0}^{k-1}\omega_k^{(i-t)*j}\binom{L}{i}[A^i]_{x,y}\\
=\frac{1}{k}\sum_{j=0}^{k-1}\omega_k^{-jt}
\sum_{i=0}^L\binom{L}{i}(\omega_k^{ij} [A^i]_{x,y})\\
=\frac{1}{k}\sum_{j=0}^{k-1}\omega_k^{-jt}[(\omega_k^jA+I)^L]_{x,y}\\
\]
其中:
1&0&0\\
0&1&0\\
0&0&1\\
\end{bmatrix}
\]
上面最后一步变换实质上就是二项式定理\(\sum_{i=0}^n\binom{n}{i}x_i=(1+x)^n\)的运用。
设:
\]
则:
\]
然后就是一个很牛逼的套路:
\]
所以:
=\frac{1}{k}\omega_k^{\binom{t}{2}}\sum_{j=0}^{k-1}\omega_k^{\binom{j}{2}}f_j\cdot\omega_k^{-\binom{t+j}{2}}
\]
\(ans_i\)的生成函数可以写成下面两个函数卷积。
G(n)=\omega_k^{-\binom{2*k-1-n}{2}}\\
\]
代码:
#include<bits/stdc++.h>
#define ll long long
#define K 200005
using namespace std;
inline ll Get() {ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
ll n,k,L,x,y,mod;
ll g,W,w[K];
ll f[K];
ll ksm(ll t,ll x) {
ll ans=1;
for(;x;x>>=1,t=t*t%mod)
if(x&1) ans=ans*t%mod;
return ans;
}
vector<int>fac;
void work(int t) {
for(int i=2,maxx=sqrt(t);i<=maxx;i++) {
if(t%i==0) fac.push_back(i);
while(t%i==0) t/=i;
}
if(t>1) fac.push_back(t);
}
ll Find_root() {
for(int i=2;i<mod;i++) {
if(ksm(i,mod-1)!=1) continue ;
int flag=1;
for(int j=0;j<fac.size();j++) {
if(ksm(i,(mod-1)/fac[j])==1) {
flag=0;
break;
}
}
if(flag) return i;
}
}
struct matrix {
ll a[4][4];
void Init() {memset(a,0,sizeof(a));}
}A,B;
matrix operator *(const matrix &a,const matrix &b) {
static matrix tem;
tem.Init();
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
for(int k=1;k<=n;k++)
tem.a[i][j]+=a.a[i][k]*b.a[k][j]%mod;
tem.a[i][j]%=mod;
}
}
return tem;
}
matrix ksm(matrix g,ll x) {
static matrix ans;
ans.Init();
for(int i=1;i<=n;i++) ans.a[i][i]=1;
for(;x;x>>=1,g=g*g)
if(x&1) ans=ans*g;
return ans;
}
ll C_2(ll n) {return n*(n-1)/2%k;}
struct Com {
long double r,v;
Com() {}
Com(long double _r,long double _v) {r=_r,v=_v;}
};
Com operator *(const Com &a,const Com &b) {return Com(a.r*b.r-a.v*b.v,a.r*b.v+a.v*b.r);}
Com operator +(const Com &a,const Com &b) {return Com(a.r+b.r,a.v+b.v);}
Com operator -(const Com &a,const Com &b) {return Com(a.r-b.r,a.v-b.v);}
Com operator /(const Com &a,const long double &b) {return Com(a.r/b,a.v/b);}
const long double pi=acos(-1);
void FFT(Com *a,int d,int flag) {
int n=1<<d;
static int rev[K<<2];
for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<d-1);
for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int s=1;s<=d;s++) {
int len=1<<s,mid=len>>1;
Com w(cos(2*flag*pi/len),sin(2*flag*pi/len));
for(int i=0;i<n;i+=len) {
Com t(1,0);
for(int j=0;j<mid;j++,t=t*w) {
Com u=a[i+j],v=a[i+j+mid]*t;
a[i+j]=u+v;
a[i+j+mid]=u-v;
}
}
}
if(flag==-1) {for(int i=0;i<n;i++) a[i]=a[i]/n;}
}
ll F[K<<2],G[K<<2],ans[K<<2];
void mul(ll *a,ll *b,ll *c,int d) {
Com A[K<<2],B[K<<2],C[K<<2],D[K<<2];
Com f1[K<<2],f2[K<<2],f3[K<<2],f4[K<<2];
ll maxx=sqrt(mod);
int n=1<<d;
for(int i=0;i<n;i++) {
A[i]=Com(a[i]/maxx,0);
B[i]=Com(a[i]%maxx,0);
C[i]=Com(b[i]/maxx,0);
D[i]=Com(b[i]%maxx,0);
}
FFT(A,d,1),FFT(B,d,1);
FFT(C,d,1),FFT(D,d,1);
for(int i=0;i<n;i++) {
f1[i]=A[i]*C[i];
f2[i]=A[i]*D[i];
f3[i]=B[i]*C[i];
f4[i]=B[i]*D[i];
}
FFT(f1,d,-1),FFT(f2,d,-1);
FFT(f3,d,-1),FFT(f4,d,-1);
for(int i=0;i<n;i++) {
c[i]=((ll)(f1[i].r+0.5)*maxx%mod*maxx%mod+(ll)(f2[i].r+0.5)*maxx%mod+(ll)(f3[i].r+0.5)*maxx+(ll)(f4[i].r+0.5))%mod;
}
}
int main() {
n=Get(),k=Get(),L=Get(),x=Get(),y=Get(),mod=Get();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
A.a[i][j]=Get();
work(mod-1);
g=Find_root();
w[0]=1;
w[1]=ksm(g,(mod-1)/k);
for(int i=2;i<k;i++) w[i]=w[i-1]*w[1]%mod;
for(int j=0;j<k;j++) {
B=A;
for(int i=1;i<=n;i++) {
for(int k=1;k<=n;k++) {
B.a[i][k]=B.a[i][k]*w[j];
if(i==k) B.a[i][k]++;
B.a[i][k]%=mod;
}
}
B=ksm(B,L);
f[j]=B.a[x][y];
}
for(int i=0;i<k;i++) F[i]=w[C_2(i)]*f[i]%mod;
for(int i=0;i<2*k;i++) G[i]=w[(k-C_2(i))%k]%mod;
reverse(G,G+2*k);
int d=ceil(log2(3*k));
mul(F,G,ans,d);
ll invk=ksm(k,mod-2);
for(int i=0;i<k;i++) {
cout<<ans[2*k-1-i]*invk%mod*w[C_2(i)]%mod<<"\n";
}
return 0;
}
Loj 3058. 「HNOI2019」白兔之舞的更多相关文章
- LOJ 3058 「HNOI2019」白兔之舞——单位根反演+MTT
题目:https://loj.ac/problem/3058 先考虑 n=1 怎么做.令 a 表示输入的 w[1][1] . \( ans_t = \sum\limits_{i=0}^{L}C_{L} ...
- 「loj3058」「hnoi2019」白兔之舞
题意 有一个\((L+1)*n\) 的网格图,初始时白兔在\((0,X)\) , 每次可以向横坐标递增,纵坐标随意的位置移动,两个位置之间的路径条数只取决于纵坐标,用\(w(i,j)\) 表示,如果要 ...
- LOJ3058. 「HNOI2019」白兔之舞 [DP,MTT]
LOJ 前置知识:任意长度NTT 普通NTT只能做\(2^k\)的循环卷积,尝试扩展成长度为\(n\)的循环卷积,保证模意义下\(\omega_n\)存在. 不管怎样还是要算点值.推式子: \[ \b ...
- Loj #3059. 「HNOI2019」序列
Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...
- Loj #3056. 「HNOI2019」多边形
Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...
- Loj #3055. 「HNOI2019」JOJO
Loj #3055. 「HNOI2019」JOJO JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 ...
- Loj #3057. 「HNOI2019」校园旅行
Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...
- LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分
题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...
- LOJ 3057 「HNOI2019」校园旅行——BFS+图等价转化
题目:https://loj.ac/problem/3057 想令 b[ i ][ j ] 表示两点是否可行,从可行的点对扩展.但不知道顺序,所以写了卡时间做数次 m2 迭代的算法,就是每次遍历所有不 ...
随机推荐
- 所有人都可以是开发人员——《Office 365开发入门指南》视频教程即将上市
今天是春节假期的最后一天,在这里给全国的朋友们拜个晚年,祝大家身体健康,晚年幸福啊.这个春节大家过的怎么样啊,我自己是在老家过的年,家乡的年味还是比较浓的,也再次感谢朋友圈的大家给我看了各地的风光 ...
- [nodejs] nodejs开发个人博客(三)载入页面
模板引擎 使用ejs作为我们博客的前端模板引擎,用来从json数据生成html字符串 安装:npm install ejs -save 使用:入口文件中写入下面代码,定义/view/目录为视图目录 / ...
- Java学习笔记之——Manth类和String类
(1) Math:常用的数学运算,都是静态方法 方法摘要 static double abs(double a) 返回 double 值的绝对值. static float abs(float a) ...
- ubuntu中subline无法使用搜狗输入法
今天使用subline编写python程序,发现在ubuntu下无法调用搜狗输入法输入中文,结果一番搜索发现github上的sublime-text-imfix项目能修复此问题,项目地址是:https ...
- C#设计模式之十五迭代器模式(Iterator Pattern)【行为型】
一.引言 今天我们开始讲“行为型”设计模式的第三个模式,该模式是[迭代器模式],英文名称是:Iterator Pattern.还是老套路,先从名字上来看看.“迭代器模式”我第一次看到这个名称,我的理解 ...
- 预览github代码
方法一:最简单的方法,在代码的url前面加上: http://htmlpreview.github.com/? 方法二: 使用Githubpages, 方法一有可能会修改css样式,不过方法二略复杂, ...
- linux查看用户、创建用户、设置密码、修改用户、删除用户命令
查看用户 /etc/passwd /etc/shadow id alex ' |passwd --stdin alex # 设置密码,不需要交互 [root@localhost ~]# tail -l ...
- Ios12怎么投屏到电脑 苹果手机投屏电脑的方法
苹果手机是一款外观精致时尚的手机,吸引这许多用户争先恐后的购买,然后苹果手机的系统不同于我们传统使用的安卓系统,它采用的是苹果自主研发的IOS系统,有许多操作与安卓手机不同,那么苹果手机怎么用呢?下面 ...
- SuperMap iClient for JavaScript image出图
SuperMap iClient for JavaScript 客户端基于openlayers 开发. 目前最高版本为811,9D产品后推荐客户使用leaflet.openlayers客户端开发. 问 ...
- Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AOP编程比较
本篇博文用一个稍复杂点的案例来对比一下基于XML配置与基于AspectJ注解配置的AOP编程的不同. 相关引入包等Spring AOP编程准备,请参考小编的其他博文,这里不再赘述. 案例要求: 写一 ...