一道清真的数论题

LOJ #3058

Luogu P5293


题解

考虑$ n=1$的时候怎么做

设$ s$为转移的方案数

设答案多项式为$\sum\limits_{i=0}^L (sx)^i\binom{L}{i}=(sx+1)^L$

答案相当于这个多项式模$ k$的各项系数的和

发现这和LJJ学二项式定理几乎一模一样

我上一题的题解

然而直接搞是$ k^2$的,无法直接通过本题

以下都用$ w$表示$ k$次单位根

设$ F_i$为次数模$ k$为$ i$的项的系数和

单位根反演一下得到$F(i)=\sum\limits_{j=0}^{k-1}w^{-ij}(sw^j+1)^L$

组合数有个非常优美的性质

$$ij=\binom{i+j}{2}-\binom{i}{2}-\binom{j}{2}$$

推波式子

$$
\begin{aligned}
F(i)&=\sum_{j=0}^{k-1}w^{-ij}(sw^j+1)^L\\
&=\sum_{j=0}^{k-1}w^{\binom{i}{2}+\binom{j}{2}-\binom{i+j}{2}}(sw^j+1)^L\\
&=w^\binom{i}{2}\sum_{j=0}^{k-1}w^{-\binom{i+j}{2}}w^\binom{j}{2}(sw^j+1)^L\\
\end{aligned}
$$

发现这是一个差卷积的形式

扔一个$ MTT$上去就能拿那$ 40$分了

考虑$ n>1$的情况

相当于把$ s$从一个数变成了矩阵,把$ 1$变成单位矩阵

$ (sw^j+1)^L$这个矩阵我们只需要关注一个位置上的值

因此可以乘出来然后取[x][y]这个位置上的数即可

这样就可以通过此题

复杂度:大常数单 $\log$


代码

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#define rt register int
#define ll long long
using namespace std;
inline ll read(){
ll x=;char zf=;char ch=getchar();
while(ch!='-'&&!isdigit(ch))ch=getchar();
if(ch=='-')zf=-,ch=getchar();
while(isdigit(ch))x=x*+ch-'',ch=getchar();return x*zf;
}
void write(ll y){if(y<)putchar('-'),y=-y;if(y>)write(y/);putchar(y%+);}
void writeln(const ll y){write(y);putchar('\n');}
int k,m,n,x,y,cnt,p,L;
int w[],val[];
int f[],g[],F[];
int ksm(int x,int y=p-){
int ans=;
for(;y;y>>=,x=1ll*x*x%p)if(y&)ans=1ll*ans*x%p;
return ans;
}
struct mat{
ll a[][];
void print(){
for(rt i=;i<n;i++)for(rt j=;j<n;j++)cout<<a[i][j]<<" \n"[j==n-];
}
inline mat operator*(const mat s)const{
mat ret={};
for(rt i=;i<n;i++)
for(rt k=;k<n;k++)
for(rt j=;j<n;j++)
(ret.a[i][j]+=a[i][k]*s.a[k][j]);
for(rt i=;i<n;i++)for(rt j=;j<n;j++)ret.a[i][j]%=p;
return ret;
}
mat operator*(const int s)const{
mat ret;
for(rt i=;i<n;i++)
for(rt j=;j<n;j++)
ret.a[i][j]=a[i][j]*s%p;
return ret;
}
mat operator+(const mat s)const{
mat ret;memset(ret.a,,sizeof(ret.a));
for(rt i=;i<n;i++)
for(rt j=;j<n;j++)
ret.a[i][j]=(a[i][j]+s.a[i][j])%p;
return ret;
} }I,zy;
mat ksm(mat x,int y){
mat ans=I;
for(;y;y>>=,x=x*x)if(y&)ans=ans*x;
return ans;
}
int V(int x){
return 1ll*x*(x-)/%k;
}
const double PI=acos(-1.0);
struct cp{
double x,y;
cp operator +(const cp &s)const{return {x+s.x,y+s.y};}
cp operator -(const cp &s)const{return {x-s.x,y-s.y};}
cp operator *(const cp &s)const{return {x*s.x-y*s.y,x*s.y+y*s.x};}
}W[][<<],A[],B[],C[],D[];
int R[];
void FFT(const int n,cp *A){
for(rt i=;i<n;i++)if(i>R[i])swap(A[i],A[R[i]]);
for(rt j=;j<n;j+=){
const cp x=A[j],y=A[j+];
A[j]=x+y,A[j+]=x-y;
}
for(rt i=,s=;i<n;i<<=,s++)
for(rt j=;j<n;j+=i<<)
for(rt k=;k<i;k+=){
cp x=A[j+k],y=W[s][k]*A[i+j+k];
A[j+k]=x+y;A[i+j+k]=x-y;
x=A[j+k+],y=W[s][k+]*A[i+j+k+];
A[j+k+]=x+y;A[i+j+k+]=x-y;
}
}
int yg(int n){
for(rt i=;i<=n;i++){
for(rt j=;j*j<=n;j++)if((n-)%j==)
if(ksm(i,(n-)/j)==)goto end;
return i;end:;
}
}
void subtask(){
w[]=;w[]=ksm(yg(p),(p-)/k);
for(rt i=;i<k;i++)w[i]=1ll*w[i-]*w[]%p;mat s=zy;
for(rt i=;i<k;i++){
g[i]=ksm(s*w[i]+I,L).a[x-][y-]*w[V(i)]%p;
}
for(rt i=;i<k+k;i++)f[i]=w[(k-V(i))%k];
for(rt i=;i<k/;i++)swap(g[i],g[k-i]); n=k+k-;m=k;
int lim=;while(lim<=n+m)lim<<=;
for(rt i=;(<<i)<lim;i++){
W[i][]={,};
W[i][]={cos(PI/(<<i)),sin(PI/(<<i))};
for(rt j=;j<<<i;j++)
if(j%==)W[i][j]={cos(PI*j/(<<i)),sin(PI*j/(<<i))};
else W[i][j]=W[i][j-]*W[i][];
} for(rt i=;i<=n;i++){
A[i].x=f[i]>>;
A[i].y=f[i]&;
}
for(rt i=;i<=m;i++){
B[i].x=g[i]>>;
B[i].y=g[i]&;
}
for(rt i=;i<lim;i++)R[i]=(R[i>>]>>)|(i&)*(lim>>);
FFT(lim,A);FFT(lim,B);
for(rt i=;i<lim;i++){
const int pl=(lim-)&(lim-i);
const cp ca={A[pl].x,-A[pl].y},cb={B[pl].x,-B[pl].y};
const cp a=(A[i]+ca)*(cp){0.5,},b=(A[i]-ca)*(cp){,-0.5},
c=(B[i]+cb)*(cp){0.5,},d=(B[i]-cb)*(cp){,-0.5};
C[pl]=a*c+a*d*(cp){,};D[pl]=b*c+b*d*(cp){,};
}
FFT(lim,C);FFT(lim,D);
for(rt i=k;i<k+k;i++){
const int vv=1ll*w[V(i-k)]*ksm(k,p-)%p;
ll a=C[i].x/lim+0.5,b=C[i].y/lim+0.5,c=D[i].x/lim+0.5,d=D[i].y/lim+0.5;
a=((a%p)<<)+(((b+c)%p)<<)+d;a=(a%p+p)%p;
writeln(1ll*a*vv%p);
}
exit();
}
int jc[],njc[],inv[],ff[][],ans[];
int c(int x,int y){
return 1ll*jc[x]*njc[y]%p*njc[x-y]%p;
}
void bl(){
for(rt i=;i<;i++)jc[i]=njc[i]=inv[i]=;
for(rt i=;i<=L;i++){
jc[i]=1ll*jc[i-]*i%p;
inv[i]=1ll*inv[p%i]*(p-p/i)%p;
njc[i]=1ll*njc[i-]*inv[i]%p;
}
ff[][x-]=;if(x==y)ans[]=;
for(rt i=;i<=L;i++)
for(rt j=;j<n;j++){
for(rt k=;k<n;k++)
(ff[i][j]+=1ll*zy.a[k][j]*ff[i-][k]%p)%=p;
if(j==y-)(ans[i%k]+=1ll*ff[i][j]*c(L,i)%p)%=p;
}
for(rt i=;i<k;i++)writeln(ans[i]);exit();
}
int main(){
cin>>n>>k>>L>>x>>y>>p;
for(rt i=;i<n;i++)
for(rt j=;j<n;j++)
cin>>zy.a[i][j];
if(L<=)bl();
for(rt i=;i<n;i++)I.a[i][i]=;
subtask();
return ;
}

「HNOI 2019」白兔之舞的更多相关文章

  1. LOJ#3054. 「HNOI 2019」鱼

    LOJ#3054. 「HNOI 2019」鱼 https://loj.ac/problem/3054 题意 平面上有n个点,问能组成几个六个点的鱼.(n<=1000) 分析 鱼题,劲啊. 容易想 ...

  2. Solution -「HNOI 2019」「洛谷 P5293」白兔之舞

    \(\mathcal{Description}\)   Link.   不想概括题意.jpg \(\mathcal{Solution}\)   定义点集 \(S_c=\{(u,v)|v=c\}\):第 ...

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

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

  4. 「WC 2019」数树

    「WC 2019」数树 一道涨姿势的EGF好题,官方题解我并没有完全看懂,尝试用指数型生成函数和组合意义的角度推了一波.考场上只得了 44 分也暴露了我在数数的一些基本套路上的不足,后面的 \(\ex ...

  5. #3146. 「APIO 2019」路灯

    #3146. 「APIO 2019」路灯 题目描述 一辆自动驾驶的出租车正在 Innopolis 的街道上行驶.该街道上有 \(n + 1\) 个停车站点,它们将街道划分成了 \(n\) 条路段.每一 ...

  6. #3145. 「APIO 2019」桥梁

    #3145. 「APIO 2019」桥梁 题目描述 圣彼得堡市内所有水路长度总和约 282 千米,市内水域面积占城市面积的 7%.--来自维基百科 圣彼得堡位于由 \(m\) 座桥梁连接而成的 \(n ...

  7. #3144. 「APIO 2019」奇怪装置

    #3144. 「APIO 2019」奇怪装置 题目描述 考古学家发现古代文明留下了一种奇怪的装置.该装置包含两个屏幕,分别显示两个整数 \(x\) 和 \(y\). 经过研究,科学家对该装置得出了一个 ...

  8. 【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)

    [题解]#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT) 之前做这道题不理解,有一点走火入魔了,甚至想要一本近世代数来看,然后通过人类智慧思考后发现, ...

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

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

随机推荐

  1. 【转】C# 定时器事件(设置时间间隔,间歇性执行某一函数,控制台程序)

    using System.Timers;定时器事件代码 static void Main(string[] args) { Method(); #region 定时器事件 Timer aTimer = ...

  2. 随机数据生成与对拍【c++版,良心讲解】

    10.7更新:见最下面 离NOIP2018没剩多长时间了,我突然发现我连对拍还不会,于是赶紧到网上找资料,找了半天发现了一个特别妙的程序,用c++写的! 不过先讲讲随机数据生成吧. 很简单,就是写一个 ...

  3. Python爬虫爬取网页图片

    没想到python是如此强大,令人着迷,以前看见图片总是一张一张复制粘贴,现在好了,学会python就可以用程序将一张张图片,保存下来. 今天逛贴吧看见好多美图,可是图片有点多,不想一张一张地复制粘贴 ...

  4. UML在代码中的展现

    依赖:一个类使用了另外一个类,这种关系是临时的.脆弱的. 如人需要过河,需要船,这时人.过河(船)  中船被当做参数传入,船的实现变化会影响过河方法.     聚合:体现是整体与部分.has-a的关系 ...

  5. 类String 常用方法

    字符串当中的常用方法之比较相关的方法 public boolean equals (object obj):将此字符串与指定的对象进行比较(只有参数是字符串并且内容相同才会返回true) public ...

  6. linux安装redis操作

    redis官网地址:http://www.redis.io/ 最新版本:2.8.3 在Linux下安装Redis非常简单,具体步骤如下(官网有说明): 1.下载源码,解压缩后编译源码. $ wget ...

  7. Ubuntu常用软件

    //latex公式识别 sudo snap install mathpix-snipping-tool //markdown # or run: # sudo apt-key adv --keyser ...

  8. EntityFrameworkCore中的OnModelCreating

    在我们使用EntityFrameworkCore作为数据库ORM框架的时候,不可避免的要重载DbContext中的一个虚方法OnModelCreating,那么这个方法到底是做什么的?到底有哪些作用呢 ...

  9. java核心卷笔记--P48字符串3.6.5

    一定不要使用 == 运算符检测两个字符串是否相等 ! 这个运算符只能够确定两个字串是否放置在同一个位置上 . 当然 , 如果字符串放置在同一个位置上 , 它们必然相等. 但是 ,完全有可能将内容相同的 ...

  10. 树 相关知识总结以及Java实现

    最近在温习树相关的知识,并且用java实现了一下树的遍历相关,先贴上代码供大家参考吧. package tree_problems; import java.util.ArrayDeque; impo ...