【Luogu5293】[HNOI2019] 白兔之舞
题目描述
略
Sol
考场上暴力 \(O(L)\) 50分真良心。
简单的推一下式子,对于一个 t 来说,答案就是:
\]
就是对于所有 mod k 的结果是 t 的 i 的后面那一坨东西的和。
\(F(i)\) 表示走了 \(i\) 步从纵坐标 x 到纵坐标为 y 的方案数,这个东西显然非常好递推。
所以 \(O(L)\) 的暴力做法就直接递推组合数就行了。
然后是正解。
\([k|(i-t)]\)这玩意可以套用单位根的性质: \([k|n]=\frac{1}{k}\sum_{i=0}^kw_k^{in}\)
正确性结合单位根性质和等比数列求和就可以得到。
所以式子就变成了:
\]
显而易见的把里面拆了然后交换求和顺序:
\]
后面的东西是个套路,具体见 bzoj3328 PYXFIB
我们把 \(F(i)\) 写乘一个矩阵幂次的形式,因为是可以矩阵乘法递推的。
假设转移矩阵是 \(T\)
\]
真正的 \(F(i)\) 就是 \(T^i[x][y]\)
后面就是一个组合数+幂次项,是一个的二项式定理的形式,合并一下就是:
\]
\(I\) 是单位矩阵。
后面的东西对于一个 \(j\) 而言显然是固定的, 我们设 \(G(w_k^j)=(Tw_k^j+I)^L\)
所以要求的是:
\]
这玩意看上去好眼熟啊。不就是个 \(IDFT\) 吗?
我们 \(IDFT\) 就是对于求出点值后的多项式代入单位根的倒数,最后结果乘上 \(\frac{1}{n}\)。
所以就是这么回事了。就是让我们对求完后的 \(G(x)\) 给 \(IDFT\) 一下回去就是所有 \(t\) 的答案了
所以问题变成求解任意长度的 \(DFT\) ,这里我们就没有办法用 性能优化 那题的方法 \(DFT\) 了
然后就可以使用 \(Bluestein’s\; Algorithm\) 了。(具体可参见我的性能优化的题解)
注意矩阵里面的运算要卡常,先用 long long 存下答案再取模,不然常数大不开 O2 过不了。(出这种毒瘤题也就算了怎么还卡常啊QAQ)
code:
#include<bits/stdc++.h>
using namespace std;
#define Set(a,b) memset(a,b,sizeof(a))
template<class T>inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}typedef long long ll;
int mod;const int MAXN=65536;
template<class T>inline void Inc(T&x,int y){x+=y;if(x>=mod) x-=mod;}
template<class T>inline void Dec(T&x,int y){x-=y;if(x < 0 ) x+=mod;}
template<class T>inline int fpow(int x,T k){int ret=1;for(;k;k>>=1,x=(ll)x*x%mod)if(k&1) ret=(ll)ret*x%mod;return ret;}
inline int Sum(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline int Dif(int x,int y){x-=y;if(x < 0 ) x+=mod;return x;}
int n,k,L,x,y,w[3][3];
int F[MAXN],g,wn[MAXN],iwn[MAXN];
inline void Getroot(){
int phi=mod-1;int x=phi;
static int pri[50],cnt=0;
for(int i=2;i*i<=x;++i) {
if(x%i==0) {pri[++cnt]=i,x/=i;while(x%i==0) x/=i;}
}
for(g=2;;++g){bool fl=1;
for(int i=1;i<=cnt;++i) if(fpow(g,phi/pri[i])==1) {fl=0;break;}
if(fl)return;
}
}
namespace Work1{
struct matrix{
ll a[3][3];matrix(){Set(a,0);}
inline ll* operator [](int x){return a[x];}
inline matrix operator +(matrix b){matrix c;for(int i=0;i<n;++i) for(int j=0;j<n;++j) c[i][j]=Sum(a[i][j],b[i][j]);return c;}
inline matrix operator *(matrix b){
matrix c;
for(int i=0;i<n;++i)
for(int j=0;j<n;++j){
for(int k=0;k<n;++k) c[i][j]+=a[i][k]*b[k][j];
c[i][j]%=mod;
}
return c;
}
}T,I;
inline matrix matrixfpow(matrix x,int k){matrix ret=I;for(;k;k>>=1,x=x*x)if(k&1)ret=ret*x;return ret;}
inline void work(){
for(int i=0;i<n;++i) I[i][i]=1;
for(int i=0;i<k;++i) {T=matrix();
for(int u=0;u<n;++u)for(int v=0;v<n;++v) T[u][v]=(ll)w[u][v]*wn[i]%mod;
T=T+I;T=matrixfpow(T,L);F[i]=T[x][y];
}
return;
}
}
namespace Work2{
const int MAXM=MAXN<<2;
typedef double db;int rader[MAXM];
inline int Init(int n){
int len=1,up=-1;while(len<=n) len<<=1,++up;
for(int i=1;i<len;++i) rader[i]=(rader[i>>1]>>1)|((i&1)<<up);
return len;
}
namespace MTT{
const db PI=acos(-1);
struct Complex{
db x,y;Complex(db _x=0.0,db _y=0.0){x=_x,y=_y;}
inline Complex operator +(const Complex B){return Complex(x+B.x,y+B.y);}
inline Complex operator -(const Complex B){return Complex(x-B.x,y-B.y);}
inline Complex operator *(const Complex B){return Complex(x*B.x-y*B.y,x*B.y+y*B.x);}
}w[MAXM];
inline void Calc(int n){for(int i=1;i<n;i<<=1) for(int j=0;j<i;++j) w[n/i*j]=Complex(cos(PI/i*j),sin(PI/i*j));return;}
inline void FFT(Complex*A,int n,int f){
for(int i=0;i<n;++i) if(rader[i]>i) swap(A[rader[i]],A[i]);
for(int i=1;i<n;i<<=1)
for(int j=0,p=i<<1;j<n;j+=p)
for(int k=0;k<i;++k){
Complex X=A[j|k],Y=A[j|k|i]* ((~f)? w[n/i*k]:Complex(w[n/i*k].x,-w[n/i*k].y));
A[j|k]=X+Y,A[j|k|i]=X-Y;
}
if(!~f) for(int i=0;i<n;++i) A[i].x/=(db)n;return;
}
inline void Mul(int*A,int*B,int*C,int len){
static Complex A1[MAXM],A2[MAXM],B1[MAXM],B2[MAXM];
int MO=sqrt(mod);
for(int i=0;i<len;++i) A1[i]=Complex(A[i]/MO,0.0),B1[i]=Complex(A[i]%MO,0.0),A2[i]=Complex(B[i]/MO,0.0),B2[i]=Complex(B[i]%MO,0.0);
FFT(A1,len,1),FFT(A2,len,1),FFT(B1,len,1),FFT(B2,len,1);
for(int i=0;i<len;++i) {Complex X;
X=A1[i]*A2[i],A2[i]=A2[i]*B1[i];
B1[i]=B1[i]*B2[i];B2[i]=B2[i]*A1[i];
A1[i]=X,A2[i]=A2[i]+B2[i];
}int MOD=MO*MO%mod;
FFT(A1,len,-1),FFT(B1,len,-1),FFT(A2,len,-1);
for(int i=0;i<len;++i) {
int X=(ll)(A1[i].x+0.5)%mod,Y=(ll)(B1[i].x+0.5)%mod,Z=(ll)(A2[i].x+0.5)%mod;
int ans=(ll)MOD*X%mod;Inc(ans,(ll)MO*Z%mod);Inc(ans,Y);
C[i]=ans;
}return;
}
}using MTT::Calc;
inline int Co(int x){return (ll)x*(x-1)/2%k;}
inline void DFT(int*A,int n,int len){
int m=2*n-1;static int F[MAXM],G[MAXM];
for(int i=0;i<n;++i) F[i]=(ll)A[i]*wn[Co(i)]%mod;for(int i=n;i<len;++i) F[i]=0;
for(int i=0;i<m;++i) G[i]=iwn[Co(i)];for(int i=m;i<len;++i) G[i]=0;
reverse(F,F+n);MTT::Mul(F,G,F,len);
for(int k=0,i=n-1;i<m;++i,++k) A[k]=(ll)F[i]*wn[Co(k)]%mod;
for(int i=0,inv=fpow(n,mod-2);i<n;++i) A[i]=(ll)A[i]*inv%mod;
return;
}
void work(){
int len=Init(3*k-3);Calc(len);DFT(F,k,len);
for(int i=0;i<k;++i) printf("%d\n",F[i]);
return;
}
}
int main()
{
freopen("dance.in","r",stdin);
freopen("dance.out","w",stdout);
init(n),init(k),init(L),init(x),init(y),init(mod);--x,--y;Getroot();
wn[0]=iwn[0]=1,wn[1]=fpow(g,(mod-1)/k),iwn[1]=fpow(wn[1],mod-2);
for(int i=2;i<k;++i) wn[i]=(ll)wn[i-1]*wn[1]%mod,iwn[i]=(ll)iwn[i-1]*iwn[1]%mod;
for(int i=0;i<n;++i) for(int j=0;j<n;++j) init(w[i][j]);
Work1::work();Work2::work();
return 0;
}
【Luogu5293】[HNOI2019] 白兔之舞的更多相关文章
- HNOI2019 白兔之舞 dance
HNOI2019 白兔之舞 dance 显然\(n=3\)就是\(n=1\)的扩展版本,先来看看\(n=1\)怎么做. 令\(W=w[1][1]\),显然答案是:\(ans_t=\sum_{i\mod ...
- luogu P5293 [HNOI2019]白兔之舞
传送门 关于这题答案,因为在所有行,往后跳到任意一行的\(w_{i,j}\)都是一样的,所以可以算出跳\(x\)步的答案然后乘上\(\binom{l}{x}\),也就是枚举跳到了哪些行 如果记跳x步的 ...
- [HNOI2019]白兔之舞
memset0 多合一无聊题 mod k=t,并且k是p-1的约数 单位根反演石锤了. 所以直接设f[i]表示走i步的方案数, 然后C(L,i)分配位置,再A^i进行矩乘得到f[i] 变成生成函数F( ...
- [HNOI2019]白兔之舞(矩阵快速幂+单位根反演)
非常抱歉,这篇文章鸽了.真的没时间写了. #include<bits/stdc++.h> using namespace std; typedef long long ll; #defin ...
- Loj 3058. 「HNOI2019」白兔之舞
Loj 3058. 「HNOI2019」白兔之舞 题目描述 有一张顶点数为 \((L+1)\times n\) 的有向图.这张图的每个顶点由一个二元组 \((u,v)\) 表示 \((0\le u\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 3058 「HNOI2019」白兔之舞——单位根反演+MTT
题目:https://loj.ac/problem/3058 先考虑 n=1 怎么做.令 a 表示输入的 w[1][1] . \( ans_t = \sum\limits_{i=0}^{L}C_{L} ...
- 「HNOI 2019」白兔之舞
一道清真的数论题 LOJ #3058 Luogu P5293 题解 考虑$ n=1$的时候怎么做 设$ s$为转移的方案数 设答案多项式为$\sum\limits_{i=0}^L (sx)^i\bin ...
随机推荐
- 平时碰到系统CPU飙高和频繁GC,你会怎么排查?
处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题.当然,这些问题的最终导致的直观现象就是系统运行缓慢,并且有大量的报警.本文主要针对系统运行缓慢这 ...
- Spring获取request、session以及servletContext
获取request: HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestA ...
- jQuery验证控件jquery.validate.js汉化
如需要修改,可在js代码中加入: jQuery.extend(jQuery.validator.messages, { required: "必选字段", remote: &q ...
- 【ABAP系列】SAP ABAP 实现FTP的文件上传与下载
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 实现FTP的文 ...
- 【Linux开发】【Qt开发】tslibs的配置(触摸屏没有,HDMI屏幕):Qt界面响应USB鼠标
s3c2416 linux qt4.x 由于触摸屏坏了,板子只能用鼠标了,结果以前可以用的现在鼠标突然不能用了 为此交叉编译了qt的多个版本,也换过根文件系统,以为是tslib版本的问题,却发现q ...
- 刘铁猛-深入浅出WPF-系列资源汇总
首先奉上原作者刘铁猛博客地址:http://www.cnblogs.com/prism/ 作者讲的很不错,没有之一,另外作者出了一本书,希望大家支持. 送上全套高清晰视频教程(我注册了3个51cto的 ...
- 深入理解Linux-hostname
当我觉得对Linux系统下修改hostname已经非常熟悉的时候,今天碰到了几个个问题,这几个问题给我好好上了一课,很多知识点,当你觉得你已经掌握的时候,其实你了解的还只是皮毛.技术活,切勿浅尝则止! ...
- [转帖]Ubuntu 清理 历史命令
Ubuntu彻底清除history命令历史记录 https://blog.csdn.net/u013554213/article/details/84954062 centos 可以使用这个命令 清理 ...
- FTP-学习笔记(1)
1.简单的SFTP.FTP文件上传下载 SftpTools.java package com.lfy.mian; import com.jcraft.jsch.*; import java.io.Fi ...
- DateHandler日期处理工具(JSP中使用后台工具类)
1.DateHandler.java package Utils.dateHandler; import java.text.ParseException; import java.text.Simp ...