题目链接

题目描述

Sol

考场上暴力 \(O(L)\) 50分真良心。

简单的推一下式子,对于一个 t 来说,答案就是:

\[\sum_{i=0}^{L} [k|(i-t)] {L\choose i}F(i)
\]

就是对于所有 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}\)

正确性结合单位根性质和等比数列求和就可以得到。

所以式子就变成了:

\[\frac{1}{k}\sum_{i=0}^{L} {L\choose i}F(i)\sum_{j=0}^k w_k^{j(i-t)}
\]

显而易见的把里面拆了然后交换求和顺序:

\[\frac{1}{k}\sum_{j=0}^k w_k^{-jt}\sum_{i=0}^{L}w_k^{ji} {L\choose i}F(i)
\]

后面的东西是个套路,具体见 bzoj3328 PYXFIB

我们把 \(F(i)\) 写乘一个矩阵幂次的形式,因为是可以矩阵乘法递推的。

假设转移矩阵是 \(T\)

\[\frac{1}{k}\sum_{j=0}^k w_k^{-jt}\sum_{i=0}^{L}w_k^{ji} {L\choose i}T^i
\]

真正的 \(F(i)\) 就是 \(T^i[x][y]\)

后面就是一个组合数+幂次项,是一个的二项式定理的形式,合并一下就是:

\[\frac{1}{k}\sum_{j=0}^k w_k^{-jt}(Tw_k^j+I)^L
\]

\(I\) 是单位矩阵。

后面的东西对于一个 \(j\) 而言显然是固定的, 我们设 \(G(w_k^j)=(Tw_k^j+I)^L\)

所以要求的是:

\[\frac{1}{k}\sum_{j=0}^k (w_k^{-t})^j G(w_k^j)
\]

这玩意看上去好眼熟啊。不就是个 \(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] 白兔之舞的更多相关文章

  1. HNOI2019 白兔之舞 dance

    HNOI2019 白兔之舞 dance 显然\(n=3\)就是\(n=1\)的扩展版本,先来看看\(n=1\)怎么做. 令\(W=w[1][1]\),显然答案是:\(ans_t=\sum_{i\mod ...

  2. luogu P5293 [HNOI2019]白兔之舞

    传送门 关于这题答案,因为在所有行,往后跳到任意一行的\(w_{i,j}\)都是一样的,所以可以算出跳\(x\)步的答案然后乘上\(\binom{l}{x}\),也就是枚举跳到了哪些行 如果记跳x步的 ...

  3. [HNOI2019]白兔之舞

    memset0 多合一无聊题 mod k=t,并且k是p-1的约数 单位根反演石锤了. 所以直接设f[i]表示走i步的方案数, 然后C(L,i)分配位置,再A^i进行矩乘得到f[i] 变成生成函数F( ...

  4. [HNOI2019]白兔之舞(矩阵快速幂+单位根反演)

    非常抱歉,这篇文章鸽了.真的没时间写了. #include<bits/stdc++.h> using namespace std; typedef long long ll; #defin ...

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

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

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

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

  7. LOJ3058. 「HNOI2019」白兔之舞 [DP,MTT]

    LOJ 前置知识:任意长度NTT 普通NTT只能做\(2^k\)的循环卷积,尝试扩展成长度为\(n\)的循环卷积,保证模意义下\(\omega_n\)存在. 不管怎样还是要算点值.推式子: \[ \b ...

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

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

  9. 「HNOI 2019」白兔之舞

    一道清真的数论题 LOJ #3058 Luogu P5293 题解 考虑$ n=1$的时候怎么做 设$ s$为转移的方案数 设答案多项式为$\sum\limits_{i=0}^L (sx)^i\bin ...

随机推荐

  1. leetcode 27. 移除元素(python)

    1. 题目描述 给定一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外 ...

  2. Webpack的tapable 为什么要使用 new Funtion 来生成静态代码

    为了保持代码的单态(monomorphism). 这涉及到了js引擎优化的一些问题, tapable从1.0.0版本开始就用new Function来生成静态代码最后来来执行, 以确保得到最优执行效率 ...

  3. wiki团队协作软件Confluence

    一.准备环境 准备环境 lamp(Linux.apache.mysql.php)框架 centos7 java jdk1.8.0_111 Distrib 5.5.52-MariaDB confluen ...

  4. hdu5993/2016icpc青岛L

    zz:https://www.cnblogs.com/ytytzzz/p/9674661.html 题意:给一棵树,每次询问删掉两条边,问剩下的三棵树的最大直径点10W,询问10W,询问相互独立 So ...

  5. vue分别打包测试环境和正式环境

    vue打包时使用不同的环境变量 需求 同一个项目通过打包使用不同的环境变量,目前的环境有三个: 一.本地------开发环境 二.线上------测试环境 三.线上------正式环境 我们都知道vu ...

  6. 第十一周总结 继承、this和super的区别和用法、方法的重写和重载

    一.继承 1.子类继承父类,通过一个关键字 extends 2.子类的对象可以调用父类中的(public protected)属性和方法 当作自己的来使用 3.子类可以添加自己独有的属性和方法 4.子 ...

  7. phpStudy配置sql、oracle---博主摘录

    引用 :https://www.cnblogs.com/myBlogInWork/p/8657125.html 由于工作需要,要用到php+oracle写个项目,故而有了以下内容: 本来以为php有默 ...

  8. Centos7Yum安装PHP7.2流程

    Centos7Yum安装PHP7.21.安装源 安装php72w,是需要配置额外的yum源地址的,否则会报错不能找到相关软件包. php高版本的yum源地址,有两部分,其中一部分是epel-relea ...

  9. 数塔 Easy

    在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?  已经告诉你了,这是个DP的题 ...

  10. textarea标签输出内容时不能顶格(左对齐)输出

    我用textarea输出文本内容的时候出现下面的问题:文本内容在action里测试没有问题(文本内容前面没有空格),但是在jsp页面textare标签中输出文本内容时,文本内容前面却出现一些多余的空格 ...