LOJ

前置知识:任意长度NTT

普通NTT只能做\(2^k\)的循环卷积,尝试扩展成长度为\(n\)的循环卷积,保证模意义下\(\omega_n\)存在。

不管怎样还是要算点值。推式子:

\[\begin{align*}
X_i&=\sum_{j=0}^{n-1}x_j\omega_n^{ij}\\
&=\sum_{j=0}^{n-1}x_j\omega_n^{{i+j\choose2}-{i\choose 2}-{j\choose 2}}\\
&=\omega_n^{-{i\choose 2}}\sum_{j=0}^{n-1}x_j\omega_n^{-{j\choose 2}}\times \omega_n^{{i+j\choose2}}
\end{align*}
\]

令\(F_i=x_i\omega_n^{-{i\choose 2}},G_i=\omega_n^{{i\choose 2}}\),那么就有\(X_i=\sum_{j=0}^{n-1} F_jG_{i+j}\),就可以任意模数NTT做了。

思路

发现什么性质都观察不出来,于是直接上DP。\(dp_{i,j,x}\)表示前\(i\)层,走了\(j\)步,走到第二维是\(x\)的点(但第一维不一定是\(i\))的方案数,有转移:

\[dp_{i,j,x}=dp_{i-1,j,x}+\sum_y dp_{i-1,j-1,y}\times w_{y,x}
\]

容易发现这连暴力分都没有……

发现\(n=1\)的时候,\(dp_i\)可以被看作是一个多项式,于是\(dp_L=(1+wx)^L\),可以写一个任意模数NTT。

怎么扩展?我们可以再记一维\(y\),把数组的意义改成在原有的基础上加\(i\)层、多走\(j\)步,从\(x\)走到\(y\)的方案数。你发现此时\(dp_{i,j,x,y}\)可以合并任意的\(k,i-k\)来完成转移,于是可以倍增。

倍增的时候容易发现\(j\)这一维是个循环卷积,可以MTT优化,于是获得了\(O(n^3K\log L\log K)\)的做法。

显然这是过不去的。我们发现题目保证了\(K|(mod-1)\),于是可以倍增的时候只存点值,只有在开头结尾搞个任意长度NTT,做到\(O(n^3K\log L)\)。

常数巨大,被标算踩爆,但是好想。

(然而标解也不怎么难想的样子?)

代码

  1. #include<bits/stdc++.h>
  2. clock_t t=clock();
  3. namespace my_std{
  4. using namespace std;
  5. #define pii pair<int,int>
  6. #define fir first
  7. #define sec second
  8. #define MP make_pair
  9. #define rep(i,x,y) for (int i=(x);i<=(y);i++)
  10. #define drep(i,x,y) for (int i=(x);i>=(y);i--)
  11. #define go(x) for (int i=head[x];i;i=edge[i].nxt)
  12. #define templ template<typename T>
  13. #define sz 273333
  14. typedef long long ll;
  15. typedef double db;
  16. typedef long double ld;
  17. mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
  18. templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
  19. templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
  20. templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
  21. templ inline void read(T& t)
  22. {
  23. t=0;char f=0,ch=getchar();double d=0.1;
  24. while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
  25. while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
  26. if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
  27. t=(f?-t:t);
  28. }
  29. template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
  30. char __sr[1<<21],__z[20];int __C=-1,__zz=0;
  31. inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
  32. inline void print(register int x)
  33. {
  34. if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
  35. while(__z[++__zz]=x%10+48,x/=10);
  36. while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
  37. }
  38. void file()
  39. {
  40. #ifdef NTFOrz
  41. freopen("a.in","r",stdin);
  42. #endif
  43. }
  44. inline void chktime()
  45. {
  46. #ifdef NTFOrz
  47. cout<<(clock()-t)/1000.0<<'\n';
  48. #endif
  49. }
  50. ll mod;
  51. ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
  52. ll inv(ll x){return ksm(x,mod-2);}
  53. // inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
  54. }
  55. using namespace my_std;
  56. ll g,Wk;
  57. vector<int>pp;
  58. bool check(ll x){for (auto t:pp) if (ksm(x,t)==1) return 0;return 1;}
  59. void getG(int K)
  60. {
  61. pp.push_back(1);
  62. for (ll i=2;i*i<=mod;++i) if ((mod-1)%i==0) pp.push_back(i),pp.push_back((mod-1)/i);
  63. ll x;
  64. do x=rnd(2ll,mod-1); while (!check(x));
  65. g=x;Wk=ksm(g,(mod-1)/K);
  66. }
  67. int n,x,y,L,K;
  68. ll w[4][4];
  69. const ld PI=acos(-1);
  70. struct Complex
  71. {
  72. ld a,b;
  73. Complex(ld x=0,ld y=0){a=x,b=y;}
  74. };
  75. inline Complex operator + (const Complex &x,const Complex &y){return Complex(x.a+y.a,x.b+y.b);}
  76. inline Complex operator - (const Complex &x,const Complex &y){return Complex(x.a-y.a,x.b-y.b);}
  77. inline Complex operator * (const Complex &x,const Complex &y){return Complex(x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a);}
  78. int r[sz],limit;
  79. void FFT_init(int N)
  80. {
  81. int l=-1;limit=1;
  82. while (limit<=N) limit<<=1,++l;
  83. rep(i,0,limit-1) r[i]=(r[i>>1]>>1)|((i&1)<<l);
  84. }
  85. void FFT(Complex *a,int type)
  86. {
  87. rep(i,0,limit-1) if (i<r[i]) swap(a[i],a[r[i]]);
  88. for (int mid=1;mid<limit;mid<<=1)
  89. {
  90. Complex Wn(cos(PI/mid),type*sin(PI/mid));
  91. for (int len=mid<<1,j=0;j<limit;j+=len)
  92. {
  93. Complex w(1,0);
  94. for (int k=0;k<mid;k++,w=w*Wn)
  95. {
  96. Complex x=a[j+k],y=w*a[j+mid+k];
  97. a[j+k]=x+y;
  98. a[j+k+mid]=x-y;
  99. }
  100. }
  101. }
  102. if (type==-1) rep(i,0,limit-1) a[i].a/=limit;
  103. }
  104. Complex A[sz],B[sz],C[sz],D[sz],E[sz],F[sz],G[sz],H[sz];
  105. void MTT(ll *a,int n,ll *b,int m,ll *ret)
  106. {
  107. FFT_init(n+m);
  108. rep(i,0,limit-1) A[i]=B[i]=C[i]=D[i]=E[i]=F[i]=G[i]=H[i]=Complex(0,0);
  109. rep(i,0,n-1) A[i].a=a[i]>>15,B[i].a=a[i]&0x7fff;
  110. rep(i,0,m-1) C[i].a=b[i]>>15,D[i].a=b[i]&0x7fff;
  111. FFT(A,1);FFT(B,1);FFT(C,1);FFT(D,1);
  112. rep(i,0,limit-1)
  113. {
  114. E[i]=A[i]*C[i];
  115. F[i]=A[i]*D[i];G[i]=B[i]*C[i];
  116. H[i]=B[i]*D[i];
  117. }
  118. FFT(E,-1);FFT(F,-1);FFT(G,-1);FFT(H,-1);
  119. rep(i,0,n+m-2)
  120. {
  121. ll x1=ll(round(E[i].a))%mod,x2=ll(round(F[i].a))%mod,x3=ll(round(G[i].a))%mod,x4=ll(round(H[i].a))%mod;
  122. ret[i]=((x1<<30)%mod+(x2<<15)%mod+(x3<<15)%mod+x4%mod+mod)%mod;
  123. }
  124. }
  125. ll tmp1[sz],tmp2[sz],tmp3[sz];
  126. int calc(int x){return 1ll*x*(x-1)/2%(mod-1);}
  127. void iDFT(ll *a)
  128. {
  129. ll w=inv(Wk);
  130. rep(i,0,K-1) tmp1[i]=a[i]*ksm(w,mod-1-calc(i))%mod;
  131. rep(i,0,K+K) tmp2[i]=ksm(w,calc(i));
  132. reverse(tmp1,tmp1+K);
  133. MTT(tmp1,K,tmp2,K+K,tmp3);
  134. rep(i,0,K-1) a[i]=ksm(w,mod-1-calc(i))*tmp3[i+K-1]%mod*inv(K)%mod;
  135. }
  136. ll dp[3][3][3][sz];
  137. void merge(int C,int A,int B)
  138. {
  139. rep(s,0,n-1) rep(t,0,n-1) rep(p,0,n-1) rep(i,0,K-1) (dp[C][s][t][i]+=dp[A][s][p][i]*dp[B][p][t][i]%mod)%=mod;
  140. rep(s,0,n-1) rep(t,0,n-1) rep(i,0,K-1) (dp[C][s][t][i]+=dp[A][s][t][i]+dp[B][s][t][i])%=mod;
  141. }
  142. void Clear(int p){rep(i,0,n-1) rep(j,0,n-1) rep(k,0,K-1) dp[p][i][j][k]=0;}
  143. void solve(int L,int p)
  144. {
  145. if (L==1)
  146. {
  147. rep(i,0,n-1) rep(j,0,n-1) rep(k,0,K-1) dp[p][i][j][k]=dp[2][i][j][k];
  148. return;
  149. }
  150. int mid=L>>1;solve(mid,p^1);
  151. Clear(p);
  152. merge(p,p^1,p^1);
  153. if (L&1)
  154. {
  155. Clear(p^1);
  156. merge(p^1,p,2);
  157. rep(i,0,n-1) rep(j,0,n-1) rep(k,0,K-1) dp[p][i][j][k]=dp[p^1][i][j][k];
  158. }
  159. }
  160. int main()
  161. {
  162. file();
  163. read(n,K,L,x,y,mod);
  164. --x,--y;getG(K);
  165. rep(i,0,n-1) rep(j,0,n-1) read(w[i][j]);
  166. rep(i,0,n-1) rep(j,0,n-1) rep(k,0,K-1) dp[2][i][j][k]=w[i][j]*ksm(Wk,k)%mod;
  167. solve(L,0);
  168. iDFT(dp[0][x][y]);
  169. if (x==y) (++dp[0][x][x][0])%=mod;
  170. rep(i,0,K-1) printf("%lld\n",dp[0][x][y][i]);
  171. return 0;
  172. }

LOJ3058. 「HNOI2019」白兔之舞 [DP,MTT]的更多相关文章

  1. Loj 3058. 「HNOI2019」白兔之舞

    Loj 3058. 「HNOI2019」白兔之舞 题目描述 有一张顶点数为 \((L+1)\times n\) 的有向图.这张图的每个顶点由一个二元组 \((u,v)\) 表示 \((0\le u\l ...

  2. 「loj3058」「hnoi2019」白兔之舞

    题意 有一个\((L+1)*n\) 的网格图,初始时白兔在\((0,X)\) , 每次可以向横坐标递增,纵坐标随意的位置移动,两个位置之间的路径条数只取决于纵坐标,用\(w(i,j)\) 表示,如果要 ...

  3. LOJ 3058 「HNOI2019」白兔之舞——单位根反演+MTT

    题目:https://loj.ac/problem/3058 先考虑 n=1 怎么做.令 a 表示输入的 w[1][1] . \( ans_t = \sum\limits_{i=0}^{L}C_{L} ...

  4. Loj #3059. 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  5. Loj #3056. 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

  6. Loj #3055. 「HNOI2019」JOJO

    Loj #3055. 「HNOI2019」JOJO JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 ...

  7. Loj #3057. 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

  8. [LOJ3054] 「HNOI2019」鱼

    [LOJ3054] 「HNOI2019」鱼 链接 链接 题解 首先想 \(O(n^3)\) 的暴力,不难发现枚举 \(A\) 和 \(D\) 后, \((B,C)\) 和 \((E,F)\) 两组点互 ...

  9. 【loj - 3056】 「HNOI2019」多边形

    目录 description solution accepted code details description 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时 ...

随机推荐

  1. 修改host文件加速访问github

    修改本地电脑系统 hosts 文件C:\Windows\System32\drivers\etc,直接在最后加入以下代码 192.30.253.112 github.com 192.30.253.11 ...

  2. 使用JDBC,完成数据库批量添加数据操作:

    第一步:定义一个key String key = "into 表名(字段1,字段2,字段3)"; 第二步:定义一个可以增长的变量 StringBuffer values = new ...

  3. Beego 学习笔记10:Easyui使用

    EasyUI使用 1>     下载EasyUI.下载地址:http://www.jeasyui.com/download/index.php 根据自己使用的是jquery还是Angular进行 ...

  4. APS应用案例|纽威阀门实现高效排产

    企业背景: 苏州纽威阀门股份有限公司(下文简称:纽威阀门)成立于1997年,总部设在江苏苏州.自成立以来一直致力于工业阀门的研发与制造,以为客户提供全套工业阀门解决方案为目标.纽威阀门通过企业的努力发 ...

  5. ApplicationContext的名称解释

    如果说BeanFactory是Spring的心脏,那么Application就是完整的身躯.ApplicationContext就是由BeanFactory派生出来的. 1.ApplicationCo ...

  6. MySQL Table--MySQL外键

    在之前的MySQL运维中,要求禁用触发器/存储过程/外键等一些数据库常见功能,因此对MySQL外键也相对比较陌生,今天特地探究下. 现有表TB001和TB002各包含6291456行数据,创建脚本如下 ...

  7. Shell 编程 基础

    本篇主要写一些shell脚本的基础知识,编程规范. 第一个shell脚本 [root@localhost ~]# vim first.sh #!/bin/bash # This is first Sh ...

  8. python中pymsql常用方法(1)

    python中pymysql模块常用方法以及其使用 首先我们知道pymysql 是python中操作数据库的模块 使用步骤分为如下几步: ​ 1.与数据库服务器建立链接 conn=pymysql.Co ...

  9. 攻防世界高手进阶之Web_python_block_chain(2018年DDCTFmini blockchain)

    打开题目大概看了一下,是有关区块链的题目, 感觉代码要格式化一下,不然没法看 代码格式化站点:https://www.html.cn/tool/js_beautify/ hash of genesis ...

  10. js--同步运动json上

    如何实现几个属性的同时变化?这个问题需要运用到json,这里我们先来简要的介绍一下json json的形式是这样的,他的元素是有一对对的键值对组成的{name1:value1,name2:value2 ...