【JZOJ4425】【HNOI2016模拟4.4】Fenwit
来源:互联网 发布:测试键盘按键软件 编辑:程序博客网 时间:2024/06/05 07:00
Description
Data Constraint
Solution
这道题很多人用FWT过了,毕竟题目名就这样……
那我们另辟蹊径,想想矩阵乘法怎么做。
我们要确定F0的任何一项j对于Ft的任何一项k的系数。那么我们发现j转移至k的途中系数只与转移a^b的1的个数有关。所以我们发现这T次转移只是个填1的问题:现在有一个T行m列的矩阵,每一行你要填上若干个1,是的最后j转移至k。那我们发现对于一个填1的问题,我们不关心她到底是什么数,因为在原本需要填1填1会使下次需要填1的地方-1,在原本需要填0填1会使下次需要填1的地方+1。于是我们设出f[i][j]表示当前做到第i步,有j个地方与要填1的系数,做一下dp。对于一个j,k而言,若j与k有x个地方需要修改,那么初始值f[0][x]=1。我们发现相邻两步的转移是相同的,所以就够除了一个矩阵,做一遍矩阵乘法就好。那么我们发现对于一个确定的k而言,只要j与k有相同的x,j是多少并不影响转移,因为初始时f[0][x]同样是1。所以我们设出s[j][p]表示与j有p为不同的数的f0的和,最后计算一下就好。
Code
#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const int maxn=(1<<20);ll a[maxn],b[maxn],c1[20][20],d[maxn],ans1[maxn],g[maxn][20];ll n,m,p,i,t,j,k,l,x,y,z,len;struct code{ ll a[19][19]; code friend operator * (code x,code y){ code z;memset(z.a,0,sizeof(z.a));int i,j,k; for (i=0;i<=18;i++) for (j=0;j<=18;j++){ for(k=0;k<=18;k++) z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%p); z.a[i][j]%=p; } return z; }}c,a1,b1;char s[maxn];void make(){ ll t=0,i,j,k=0; for (i=1;i<=len;i++){ k=k*10+(s[i]-48); s[i]=k/2+48;k%=2; } if (s[1]==48){ for (i=2;i<=len;i++) swap(s[i],s[i-1]); len--; }}void dg(){ while (len>1 || s[1]>49){ d[0]++;if (s[len]%2) d[d[0]]=1; make(); } a1=c; for (;d[0]>0;d[0]--){ a1=a1*a1; if (d[d[0]]) a1=a1*c; }}int main(){// freopen("data.in","r",stdin);freopen("data.out","w",stdout); scanf("%lld%lld%s\n",&m,&p,s+1);n=(1<<m);len=strlen(s+1); c1[0][0]=1; for (i=1;i<=m;i++){ c1[i][0]=1; for (j=1;j<=i;j++) c1[i][j]=(c1[i-1][j-1]+c1[i-1][j])%p; } for (i=0;i<n;i++) scanf("%lld",&a[i]); for (i=0;i<=m;i++) scanf("%lld",&b[i]); for (i=0;i<=m;i++) for (k=0;k<=i;k++) for (l=0;l<=m-i;l++) c.a[i][i-k+l]=(c.a[i][i-k+l]+b[k+l]*c1[i][k]%p*c1[m-i][l]%p)%p; dg(); for (i=0;i<=m;i++){ memset(b1.a[0],0,sizeof(b1.a[0])); b1.a[0][i]=1;b1=b1*a1; ans1[i]=b1.a[0][0]; } for (i=0;i<n;i++) g[i][0]=a[i]; for (i=1;i<=m;i++) for (j=i;j>0;j--) for (k=0;k<n;k++){ if (k&(1<<(i-1))) t=k-(1<<(i-1)); else t=k+(1<<(i-1)); g[t][j]=(g[t][j]+g[k][j-1])%p; } for (i=0;i<n;i++){ x=0; for (j=0;j<=m;j++) x=x+g[i][j]*ans1[j]%p; x%=p; printf("%lld\n",x); }}
阅读全文
1 0
- 【JZOJ4425】【HNOI2016模拟4.4】Fenwit
- 【HNOI2016模拟4.4】Fenwit
- 【HNOI2016模拟4.4】Stage
- 【HNOI2016模拟4.4】Alphadog
- [JZOJ4426]. 【HNOI2016模拟4.4】Stage
- 【JZOJ4426】【HNOI2016模拟4.4】Stage
- 【HNOI2016模拟4.4】Stage(几何&&倍增)
- HNOI2016模拟 disk
- 【HNOI2016模拟3.26】A
- 【HNOI2016模拟4.13】a
- 【HNOI2016模拟4.14】A
- 【JZOJ4427/HNOI2016模拟】 Alphadog
- JZOJ4446. 【HNOI2016模拟4.14】B
- 【HNOI2016模拟4.10】 K小数查询
- 【HNOI2016模拟4.10】 K小数查询
- 【HNOI2016模拟4.10】线性代数与逻辑
- 【HNOI2016模拟4.1】神奇的字符串
- Fenwit FWT+数论
- ThreadLocal源码简析
- 1022. Digital Library (30)
- Java包装类对象比较中存在的问题
- 基于Maven的Springboot项目搭建学习笔记
- Java泛型-类型擦除
- 【JZOJ4425】【HNOI2016模拟4.4】Fenwit
- Java并发之并行与并发的区别
- ShuffleNet算法详解
- 最长上升子序列1006
- Openstack4J API初体验之删除一个实例(删除一个虚拟机)
- Crazy Learning for Day 14
- 数学之美番外篇:平凡而又神奇的贝叶斯方法
- 高仿淘宝购物车分分钟让你集成
- Go 语言的Template Package