Description

Solution

我们考虑将问题一步步拆解

第一步求出\(F_{S,i}\)表示一次旅行按位与的值为S,走了i步的方案数。

第二步答案是\(F_{S,i}\)的二维重复卷积,记答案为\(S_{S,i}\),那么\(F_{S,i}\times S_{T,j}\)能够贡献到\(S_{S\&T,i+j}\)。

上下两部分是两个问题,我们分开来看。

考虑第一步

设原矩阵为A

根据定义,$$F_{S,i}=\sum\limits_{x&y=T}A^i_{x,y}$$

容易看出F是线性的,用题解的话来说,,并且内部的数乘可以移到外面

记\(f(x)\)为矩阵A的特征多项式,它是个n次多项式,根据Cayley-Hamilton定理我们有\(f(A)=0\)

可以看出F只看i这一维的话就是一个n阶线性递推。

记\(c\)就是\(x^i\)对\(f(x)\)取模的多项式系数。

我们有$$F_{S,i}=\sum\limits_{x&y=T}\sum\limits_{j=0}{n-1}c_jA{j}_{x,y}$$

这里\(A^0\)是单位矩阵,左对角线为1,因此对于任意S,\(F_{S,0}=1\)(当然在做完以后,我们是要去掉0的,因为不允许走0步)

交换主体$$F_{S,i}=\sum\limits_{j=0}{n-1}c_j\sum\limits_{x&y=T}A{j}_{x,y}$$

后面的东西就是\(F_{S,j}\)

那么就有$$F_{S,i}=\sum\limits_{j=0}^{n-1}c_jF_{S,j}$$

暴力出前n-1项的\(F\),这是\(O(n^4)\)的

求特征多项式有很多种方法就不赘述了, 一种比较好想的做法是带入n+1个值求行列式,然后高斯消元或者拉格朗日插值求出特征多项式,这也是\(O(n^4)\)的(实际上可以\(O(n^3)\))。

多项式取模每次只会乘一个x,直接计算最高次项的影响,时间是\(O(n)\)的

这样我们就在\(O(n^4+mn^2)\)的时间复杂度内做完了前半部分。

考虑第二步的问题:

\(F_{S,i}\)二维重复卷积,记答案为\(S_{S,i}\),那么\(F_{S,i}\times S_{T,j}\)能够贡献到\(S_{S\&T,i+j}\)。

如果只有第二维,那很简单,直接就是\(\sum F(x)^i={1\over 1-F(x)}\),多项式求逆就好了。

但是我们现在有了第一维

考虑将第二维固定做一遍FWT的and卷积(就是枚举第二维i,看做一个一维的集合幂\(F_i(S)\))

那么现在所有的第一维and卷积都变成了点乘,

即原本\(F_{S\&T,i+j}+=F_{S,i}\times F_{T,j}\)

现在都变成了\(F_{S,i+j}+=F_{S,i}\times F_{S,j}\)

我们发现这时再固定第一维(枚举每个S,把\(F_S(x)\)看做一个独立的多项式),那么就变成了一维的普通幂级数重复拼接,套用多项式求逆即可。

这样我们就得到了第二维重复拼接的结果,它实际上同时进行了第一维的重复卷积。

此时按照一开始做FWT的时候固定第二维,逆FWT回去,就是最终的答案。

这一部分的复杂度是\(O(mn\log m)\)的,常数比较大。

因此我们就在\(O(mn\log m+n^4+mn^2)\)的时间复杂度解决了。

Code

(BZOJ被卡常了。。写的很丑)

#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 20005
#define T 70
#define M 65536
#define L 16
#define LL long long
#define mo 998244353
using namespace std;
int n,m;
LL a[T][M+1],ny[M+1],c[T][T]; LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
return s;
}
//polynomial
LL ap[T][M+1],ans[T][M+1],cd[T],ct[T];
int n1;
namespace polynomial
{
LL wi[M+1],wg[M+1];
int bit[M+1],l2[M+1];
void prp(int num)
{
fo(i,0,num)
{
wi[i]=wg[i*(M/num)];
bit[i]=(bit[i>>1]>>1)|((i&1)<<(l2[num]-1));
}
}
void pre()
{
ny[1]=1;
fo(i,2,M) ny[i]=(-ny[mo%i]*(LL)(mo/i)%mo+mo)%mo;
fo(i,1,L) l2[1<<i]=i;
fod(i,M,2) if(!l2[i]) l2[i]=l2[i+1];
wg[0]=1,wg[1]=ksm(3,(mo-1)/M);
fo(i,2,M) wg[i]=wg[i-1]*wg[1]%mo;
}
void NTT(LL *a,bool pd,int num)
{
fo(i,0,num-1) if(i<bit[i]) swap(a[i],a[bit[i]]);
for(int m=2,h=1,l=num>>1;m<=num;h=m,m<<=1,l>>=1)
{
int c=(!pd)?l:-l;
for(int j=0;j<num;j+=m)
{
LL *x=a+j,*y=a+j+h,*w=(!pd)?wi:wi+num;
fo(i,0,h-1)
{
LL v=*y * *w%mo;
*y=(*x-v+mo)%mo;
*x=(*x+v)%mo;
x++,y++,w+=c;
}
}
}
if(pd) fo(i,0,num-1) a[i]=a[i]*ny[num]%mo;
}
void inv(int n,LL *a,LL *b)
{
static LL u1[M+1],u2[M+1];
b[0]=ksm(a[0],mo-2);
for(int m=1,t=2,num=4;m<n;m=t,t=num,num<<=1)
{
prp(num);
fo(i,0,num-1) u1[i]=u2[i]=0;
fo(i,0,m-1) u1[i]=b[i];
fo(i,0,t-1) u2[i]=a[i];
NTT(u1,0,num),NTT(u2,0,num);
fo(i,0,num-1) u1[i]=u1[i]*u1[i]%mo*u2[i]%mo;
NTT(u1,1,num);
fo(i,0,t-1) b[i]=((LL)2*b[i]-u1[i]+mo)%mo;
fo(i,t,num-1) b[i]=0;
}
}
void gmod()
{
LL v=ksm(cd[n1],mo-2)*ct[n1]%mo;
fo(i,0,n1) ct[i]=(ct[i]-v*cd[i]%mo+mo)%mo;
}
} using namespace polynomial; //matrix
LL c1[T][T],al[T][T]; namespace matrix
{
void ti()
{
static LL z[T][T];
memset(z,0,sizeof(z));
fo(i,0,n-1)
{
fo(k,0,n-1)
{
fo(j,0,n-1) z[i][j]=(z[i][j]+c1[i][k]*c[k][j])%mo;
}
}
fo(i,0,n-1) fo(j,0,n-1) c1[i][j]=z[i][j];
} LL det(int k)
{
static LL z[T][T];
memcpy(z,c,sizeof(c));
fo(i,0,n-1) z[i][i]=(z[i][i]-k+mo)%mo;
LL v=1;
fo(i,0,n-1)
{
fo(k,i,n-1)
{
if(z[k][i])
{
if(k!=i) swap(z[k],z[i]),v=-v;
break;
}
}
if(!z[i][i]) return 0;
LL vn=ksm(z[i][i],mo-2);
fo(k,i+1,n-1)
{
if(z[k][i])
{
LL v=z[k][i]*vn%mo;
fo(j,i,n-1) z[k][j]=(z[k][j]-v*z[i][j])%mo;
}
}
}
fo(i,0,n-1) v=v*z[i][i]%mo;
return v;
}
void gauss()
{
fo(i,0,n)
{
fo(k,i,n)
{
if(al[k][i])
{
if(k!=i) swap(al[k],al[i]);
break;
}
}
if(!al[i][i]) continue;
LL v=ksm(al[i][i],mo-2)%mo;
fo(k,i,n+1) al[i][k]=al[i][k]*v%mo;
fo(k,i+1,n)
{
if(al[k][i])
{
v=al[k][i];
fo(j,i,n+1) al[k][j]=(al[k][j]-v*al[i][j])%mo;
}
}
}
fod(i,n,0)
{
if(al[i][i])
{
fod(k,i-1,0)
{
if(al[k][i])
{
LL v=al[k][i];
fo(j,i,n+1) al[k][j]=(al[k][j]-v*al[i][j])%mo;
}
}
}
}
}
}
using namespace matrix; void FWT(int t,bool pd)
{
for(int m=2,h=1;m<=n;h=m,m<<=1)
for(int j=0;j<n;j+=m)
fo(i,0,h-1) a[i+j][t]=(a[i+j][t]+((!pd)?1:-1)*a[i+j+h][t]+mo)%mo;
} int main()
{
cin>>n>>m;
pre();
fo(i,0,n-1)
fo(j,0,n-1)
scanf("%lld\n",&c[i][j]),c1[i][j]=c[i][j]; fo(i,0,n)
{
LL v=i;
al[i][0]=1;
fo(j,1,n) al[i][j]=v,v=v*(LL)i%mo;
al[i][n+1]=det(i);
} gauss(); fo(i,0,n) cd[i]=al[i][n+1];
n1=n;
fo(i,0,n-1) a[i][0]=1;
while(cd[n1]==0) n1--;
fo(i,1,n1-1)
{
fo(x,0,n1-1) fo(y,0,n-1) a[x&y][i]=(a[x&y][i]+c1[x][y])%mo;
ti();
}
ct[n1-1]=1;
fo(i,n1,m)
{
fod(j,n1,1) ct[j]=ct[j-1];
ct[0]=0;
gmod();
fo(x,0,n-1) fo(j,0,n1-1) a[x][i]=(a[x][i]+ct[j]*a[x][j]%mo+mo)%mo;
} fo(i,0,n-1) a[i][0]=0;
memset(ap,0,sizeof(ap));
fo(j,1,m) FWT(j,0);
fo(i,0,n-1)
{
a[i][0]++;
fo(j,1,m) a[i][j]=-a[i][j];
inv(m+1,a[i],ap[i]);
} fo(j,1,m)
{
fo(i,0,n-1) a[i][j]=ap[i][j];
FWT(j,1);
} LL ans=0;
fo(i,0,n-1) fo(j,1,m) ans^=a[i][j];
printf("%lld\n",ans);
}

[JZOJ6088] [BZOJ5376] [loj #2463]【2018集训队互测Day 1】完美的旅行【线性递推】【多项式】【FWT】的更多相关文章

  1. 【loj2461】【2018集训队互测Day 1】完美的队列

    #2461. 「2018 集训队互测 Day 1」完美的队列 传送门: https://loj.ac/problem/2461 题解: 直接做可能一次操作加入队列同时会弹出很多数字,无法维护:一个操作 ...

  2. 【2018集训队互测】【XSY3372】取石子

    题目来源:2018集训队互测 Round17 T2 题意: 题解: 显然我是不可能想出来的……但是觉得这题题解太神了就来搬(chao)一下……Orzpyz! 显然不会无解…… 为了方便计算石子个数,在 ...

  3. @loj - 2461@ 「2018 集训队互测 Day 1」完美的队列

    目录 @description@ @solution@ @part - 0@ @part - 1@ @accepted code@ @details@ @description@ 小 D 有 n 个 ...

  4. LOJ2476. 「2018 集训队互测 Day 3」蒜头的奖杯 & LOJ2565. 「SDOI2018」旧试题(莫比乌斯反演)

    题目链接 LOJ2476:https://loj.ac/problem/2476 LOJ2565:https://loj.ac/problem/2565 题解 参考照搬了 wxh 的博客. 为了方便, ...

  5. 【LOJ2461】「2018 集训队互测 Day 1」完美的队列(分块+双指针)

    点此看题面 大致题意: 让你维护\(n\)个有限定长度的队列,每次区间往队列里加数,求每次加完后的队列里剩余元素种类数. 核心思路 这道题可以用分块+双指针去搞. 考虑求出每个操作插入的元素在队列中被 ...

  6. 洛谷 P4463 - [集训队互测 2012] calc(多项式)

    题面传送门 & 加强版题面传送门 竟然能独立做出 jxd 互测的题(及其加强版),震撼震撼(((故写题解以祭之 首先由于 \(a_1,a_2,\cdots,a_n\) 互不相同,故可以考虑求出 ...

  7. EZ 2018 05 06 NOIP2018 慈溪中学集训队互测(五)

    享受爆零的快感 老叶本来是让初三的打的,然后我SB的去凑热闹了 TM的T2写炸了(去你妹的优化),T1连-1的分都忘记判了,T3理所当然的不会 光荣革命啊! T1 思维图论题,CHJ dalao给出了 ...

  8. 【纪中集训2019.3.27】【集训队互测2018】小A的旅行(白)

    题目 描述 ​ \(0-n-1\)的图,满足\(n\)是\(2\)的整数次幂, $ i \to j $ 有 $ A_{i,j} $ 条路径: ​ 一条路径的愉悦值定义为起点和终点编号的\(and\)值 ...

  9. LOJ3069. 「2019 集训队互测 Day 1」整点计数(min_25筛)

    题目链接 https://loj.ac/problem/3069 题解 复数真神奇. 一句话题意:令 \(f(x)\) 表示以原点 \((0, 0)\) 为圆心,半径为 \(x\) 的圆上的整点数量, ...

随机推荐

  1. apicloud 和 微信小程序,你会用哪 个?

    微信 小程序开始火了,app跨平台的革命再次高涨,不得不说,不用再担心android和ios双版本开发成本,及h5的开发 和apicloud一样,不需要关注平台问题,只需要关注前端js.css就能大a ...

  2. 8 求s=a+aa+aaa+aaaa+aa...a的值

    题目:求s=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字. * 例如2+22+222+2222+22222(此时共有5个数相加),几个数相加有键盘控制.程序分析:关键是计算出每一项的 ...

  3. Hdu1874 畅通工程续 2017-04-12 18:37 48人阅读 评论(0) 收藏

    畅通工程续 Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submiss ...

  4. MFC中的一般经验之谈----OnInitialUpdate

    在MFC程序设计中,按照传统的设计,如果处理WM_PAINT消息,一般会派生一个OnPaint函数,映射到WM_PAINT消息上进行绘图处理.但是很多程序中并没有出现OnPaint,一个OnDraw函 ...

  5. linux 用户/用户组添加修改删除(ubuntu/centos)

    一.LINUX(UBUNTU/CENTOS)用户添加删除修改 1.建用户: adduser web                             //新建web用户 useradd web  ...

  6. [leetcode] 12. Merge Sorted Array

    这道题的无聊之处在于题目其实给了一些很奇怪的测试用例.比如他会给一些空的数组来,但是这个是不科学的,因为在C++中不允许定义一个空的列表,我们用的又不是那种糙又快的python,所以在这里我遇到了一些 ...

  7. Oracle 程序中超好用的日志记录TYPE,可以直接Copy使用

    创建类型名称:LOGGER_FACTORY Type 说明: CREATE OR REPLACE TYPE "LOGGER_FACTORY" AS OBJECT( v_progra ...

  8. 如何搭建eclipse+maven环境

    Maven这个个项目管理和构建自动化工具,越来越多的开发人员使用它来管理项目中的jar包.本文仅对Eclipse中如何安装.配置和使用Maven进行了介绍.完全step by step. 如果觉得本文 ...

  9. EAS系统环境的搭建

    (一)应用服务器配置 1.先建立好程序需要部署的文件夹,如D:\AppServer\,此目录下包含如下几个子目录: XClient(客户端升级程序放置的目录,此目录下应包含Config和Files子目 ...

  10. maven项目打jar包

    打包有两种方式: 1.直接 项目--右键--export,选择JAR file打包(不推荐这种方式): 这样直接打的包通过java -jar 会提示“没有主清单属性”,需要修改jar包中的MANIFE ...