uoj86 mx的组合数 (lucas定理+数位dp+原根与指标+NTT)

uoj

题目描述自己看去吧(

题解时间

首先看到 $ p $ 这么小还是质数,第一时间想到 $ lucas $ 定理。

注意 $ lucas $ 定理的另外一种写法是将数转换为 $ p $ 进制后计算$ C_{n}^{m} = \Pi C_{a_i}^{b_i} $

所以考虑对于 $ l-1 $ 和 $ r $ 各进行一次数位 $ dp $ 。

$ dp[i][j] $表示从低位起算到 $ i $ 位计算结果取模后为 $ j $ 且保证是在合法范围以内的方案数

$ dg[i][j] $ 表示从低位起算到 $ i $ 位计算结果取模后为 $ j $ 且不保证是在合法范围以内的方案数

转移方法:

对于计算到某一位 $ i $

$ n $ 已经给定,也就是说 $ b_i $ 已经确定

所以枚举 $ x $ 值在这一位对应的 $ a_i $ 设为 $ k $ ,设 $ C_{k}^{b_i}=g $

转移:

$ dg[i][j \cdot g \ mod \ p]+=dg[i-1][j] $

$ dp[i][j \cdot g \ mod \ p]+=dg[i-1][j] ( k < a_{i_{max}} ) $

$ dp[i][j \cdot g \ mod \ p]+=dp[i-1][j] ( k = a_{i_{max}} ) $

时间复杂度$ p^{2}logn $。

这个暴力好像是有50分。

然后考虑优化。

(这么毒瘤咋考虑出来的啊)

上式中的 $ j \cdot g $ 可以考虑优化掉。

这时就如毒瘤的数学题一样,我们看到p是质数,考虑直接用指标把它降维就好了。。。(啥?)

还是考虑上面的dp方程。

我们现在枚举到i位,用上面第一个转移式为例。

设 $ f[x] = \sum \limits_{ k = 0 }^{ p - 1 } [ C_{k}^{b_i} == x] $

那么转移式变成一个乘法卷积 $ dg^{'} [i] = \sum \limits_{j=0}^{p-1} \sum \limits_{g=0}^{p-1} dg[j] * f[g] * [j \cdot g \ mod \ p == i] $

上指标之后$ dg^{'} [i] = \sum \limits_{j=0}^{p-1} \sum \limits_{g=0}^{p-1} dg[j] * f[g] * [ (ln[j]+ln[g]) \ mod \ \phi(p) == i] $

然后上NTT。

注意0没有指标,求出其他答案之后用总数减一下就能求出0的答案了。

#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
typedef __int128 llint;
template<typename TP>inline void read(TP &tar)
{
TP ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=(TP)ret*10+ch-'0';ch=getchar();}
tar=ret*f;
}
namespace LarjaIX
{
const int N=70011,maxn=65536,P=30011,B=150;
const int mo=998244353,G=3;
lint fpow(lint a1,lint p1,lint m1);
void ntt(lint *f1,int tp);
int p,phi,len=1,g;llint n,l,r;
int rev[N];
int bitn[B],bitm[B],maxbit;
int fac[P],inv[P],facinv[P];
int ln[P];
int c[B][P];
lint ans[P];
lint f1[N],f2[N],dp[N],dg[N],dt[N];
lint wg[N],iwg[N];
void work(llint lim)
{
memset(dp,0,sizeof(dp));
memset(dg,0,sizeof(dg));
memset(bitn,0,sizeof(bitn));
for(int i=1;lim;i++) bitn[i]=lim%p,lim/=p,maxbit=max(maxbit,i);
dp[1]=dg[1]=1;
for(int b=1;b<=maxbit;b++)
{
memset(f1,0,sizeof(f1)),memset(f2,0,sizeof(f2));
for(int i=1;i<p;i++) f1[ln[i]]=dg[i];
for(int i=bitm[b];i<p;i++)if(c[b][i]) f2[ln[c[b][i]]]++;
ntt(f1,1),ntt(f2,1);
for(int i=0;i<len;i++) f2[i]=f1[i]*f2[i]%mo;
ntt(f2,-1);
memset(dg,0,sizeof(dg));
for(int i=0;i<len;i++) (dg[fpow(g,i%phi,p)]+=f2[i])%=mo;
memset(f2,0,sizeof(f2));
for(int i=bitm[b];i<bitn[b];i++)if(c[b][i]) f2[ln[c[b][i]]]++;
ntt(f2,1);
for(int i=0;i<len;i++) f2[i]=f1[i]*f2[i]%mo;
ntt(f2,-1);
memset(dt,0,sizeof(dt));
for(int i=0;i<len;i++) (dt[fpow(g,i%phi,p)]+=f2[i])%=mo;
if(c[b][bitn[b]])for(int i=1;i<p;i++) (dt[c[b][bitn[b]]*i%p]+=dp[i])%=mo;
memcpy(dp,dt,sizeof(dp));
}
}
int pri[P];
bool gck(int i){for(int j=1;j<=pri[0];j++) if(fpow(i,phi/pri[j],p)==1) return 0;return 1;}
int maid()
{
// freopen("sample.in","r",stdin);
// freopen("u.out","w",stdout);
read(p),read(n),read(l),read(r),phi=p-1;
//-----------------------------------------------------------------------------------------------------
fac[1]=fac[0]=inv[1]=facinv[1]=facinv[0]=1;
for(int i=2;i<p;i++) fac[i]=fac[i-1]*i%p,inv[i]=inv[p%i]*(p-p/i)%p,facinv[i]=facinv[i-1]*inv[i]%p;
//-----------------------------------------------------------------------------------------------------
while(len<=p*2) len<<=1;
for(int i=1;i<=len;i<<=1) wg[i]=fpow(G,(mo-1)/(i<<1),mo),iwg[i]=fpow(wg[i],mo-2,mo);
for(int i=1;i<len;i++) rev[i]=(rev[i>>1]>>1)|((len>>1)*(i&1));
//-----------------------------------------------------------------------------------------------------
//just get the g and ln of p
{
int tmp=phi;
for(int i=2;i*i<=tmp;i++)if(tmp%i==0)
{
pri[++pri[0]]=i;
while(tmp%i==0) tmp/=i;
}
if(tmp!=1) pri[++pri[0]]=tmp;
for(int i=1;i<p;i++) if(gck(i)){g=i;break;}
tmp=1;
for(int i=0;i<phi;i++) ln[tmp]=i,(tmp*=g)%=p;
}
//-----------------------------------------------------------------------------------------------------
{
llint tmp=n;
for(int bi=1;tmp;bi++) bitm[bi]=tmp%p,tmp/=p,maxbit=bi;//every bit of n
}
//-----------------------------------------------------------------------------------------------------
for(int i=1;i<128;i++)for(int j=bitm[i];j<p;j++) c[i][j]=fac[j]*facinv[j-bitm[i]]%p*facinv[bitm[i]]%p;
//-----------------------------------------------------------------------------------------------------
work(r);
for(int i=1;i<p;i++) ans[i]=dp[i];
work(l-1);
for(int i=1;i<p;i++) (ans[i]+=mo-dp[i])%=mo;
ans[0]=(r-l+1)%mo;
for(int i=1;i<p;i++) (ans[0]+=mo-ans[i])%=mo;
for(int i=0;i<p;i++) printf("%lld\n",ans[i]);
return 0;
}
lint fpow(lint a1,lint p1,lint m1)
{
lint ret=1;
while(p1)
{
if(p1&1ll) (ret*=a1)%=m1;
(a1*=a1)%=m1,p1>>=1;
}
return ret;
}
void ntt(lint *f1,int tp)
{
for(int i=0;i<len;i++) if(i<rev[i]) swap(f1[i],f1[rev[i]]);
lint ilen=fpow(len,mo-2,mo);
for(int i=1;i<len;i<<=1)
{
lint w0=~tp?wg[i]:iwg[i];
for(int j=0;j<len;j+=(i<<1))
{
lint w=1;
for(int k=0;k<i;k++,(w*=w0)%=mo)
{
lint w1=f1[j+k],w2=w*f1[j+k+i]%mo;
f1[j+k]=(w1+w2)%mo,f1[j+k+i]=(w1-w2+mo)%mo;
}
}
}
if(tp==-1) for(int i=0;i<len;i++) (f1[i]*=ilen)%=mo;
}
}
int main(){return LarjaIX::maid();}

uoj86 mx的组合数 (lucas定理+数位dp+原根与指标+NTT)的更多相关文章

  1. [UOJ86]mx的组合数——NTT+数位DP+原根与指标+卢卡斯定理

    题目链接: [UOJ86]mx的组合数 题目大意:给出四个数$p,n,l,r$,对于$\forall 0\le a\le p-1$,求$l\le x\le r,C_{x}^{n}\%p=a$的$x$的 ...

  2. BZOJ4737 组合数问题 【Lucas定理 + 数位dp】

    题目 组合数C(n,m)表示的是从n个物品中选出m个物品的方案数.举个例子,从(1,2,3)三个物品中选择两个物品可以有( 1,2),(1,3),(2,3)这三种选择方法.根据组合数的定义,我们可以给 ...

  3. bzoj 1902: Zju2116 Christopher lucas定理 && 数位DP

    1902: Zju2116 Christopher Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 172  Solved: 67[Submit][Stat ...

  4. [BZOJ4591][SHOI2015]超能粒子炮·改(Lucas定理+数位DP)

    大组合数取模可以想到Lucas,考虑Lucas的意义,实际上是把数看成P进制计算. 于是问题变成求1~k的所有2333进制数上每一位数的组合数之积. 数位DP,f[i][0/1]表示从高到低第i位,这 ...

  5. BZOJ4737 组合数问题(卢卡斯定理+数位dp)

    不妨不管j<=i的限制.由卢卡斯定理,C(i,j) mod k=0相当于k进制下存在某位上j大于i.容易想到数位dp,即设f[x][0/1][0/1][0/1]为到第x位时是否有某位上j> ...

  6. 【(好题)组合数+Lucas定理+公式递推(lowbit+滚动数组)+打表找规律】2017多校训练七 HDU 6129 Just do it

    http://acm.hdu.edu.cn/showproblem.php?pid=6129 [题意] 对于一个长度为n的序列a,我们可以计算b[i]=a1^a2^......^ai,这样得到序列b ...

  7. [Swust OJ 247]--皇帝的新衣(组合数+Lucas定理)

    题目链接:http://acm.swust.edu.cn/problem/0247/ Time limit(ms): 1000 Memory limit(kb): 65535   Descriptio ...

  8. BZOJ4591 SHOI2015超能粒子炮·改(卢卡斯定理+数位dp)

    注意到模数很小,容易想到使用卢卡斯定理,即变成一个2333进制数各位组合数的乘积.对于k的限制容易想到数位dp.可以预处理一发2333以内的组合数及组合数前缀和,然后设f[i][0/1]为前i位是否卡 ...

  9. Codeforces 582D - Number of Binominal Coefficients(Kummer 定理+数位 dp)

    Codeforces 题目传送门 & 洛谷题目传送门 一道数论与数位 dp 结合的神题 %%% 首先在做这道题之前你需要知道一个定理:对于质数 \(p\) 及 \(n,k\),最大的满足 \( ...

随机推荐

  1. Diary -「NOI 2021」酱油记

    雨幕浓稠 远近一白 是水雾弥漫的天 还是泡沫撑起的海   雨真大呢.   前几天去 ZH 中学集训没啥好记的,就从会合日开始叭. [Day -1]   逃出 ZH,掉入梦麟.(   高中的同学们忘记带 ...

  2. MySQL数据备份/导出 创建用户及其删除

    Mysql DCL 创建用户 create user '用户名'@'localhost(本机访问)/%(通配符任何ip地址都可访问本机) 分配权限 grant 权限 on 数据库.表名 to '用户名 ...

  3. c++ istream_iterator ostream_iterator

    istream_iterator/ostream_iterator void stream_iter_odd_even(const string &in_file, const string ...

  4. 数据分析实际案例之:pandas在泰坦尼特号乘客数据中的使用

    目录 简介 泰坦尼特号乘客数据 使用pandas对数据进行分析 引入依赖包 读取和分析数据 图形化表示和矩阵转换 简介 1912年4月15日,号称永不沉没的泰坦尼克号因为和冰山相撞沉没了.因为没有足够 ...

  5. 清理 Docker 占用的磁盘空间

    Docker 很占用空间,每当我们运行容器.拉取镜像.部署应用.构建自己的镜像时,我们的磁盘空间会被大量占用. 如果你也被这个问题所困扰,咱们就一起看一下 Docker 是如何使用磁盘空间的,以及如何 ...

  6. Android蓝牙扫码连接时,防止Activity重启

    集成了一个蓝牙的扫码枪,发现每次连接时,应用的当前Activity会销毁再次创建.调试了下, 没有监听到任何的事件,非常困惑.搜了一阵了解到是Android的一个机制. 某些设备配置可能会在运行时发生 ...

  7. Pentest Box之疑难杂症(解决)

    问题一:metasploit连不上数据库怎么破???? 1.首先找到配置路径:F:\bin\customtools (F代表:pentest box整个路径) 2. 编辑 customaliases ...

  8. 思迈特软件Smartbi光鲜亮丽的背后是什么在支撑?

    思迈特软件Smartbi是国内知名BI厂商,自2011年成立以来就以提升和挖掘客户的价值为使命,致力于为客户提供一站式商业智能平台和BI解决方案,发展到如今已经获得了来自国家.地方政府.国内外权威分析 ...

  9. 【C# Parallel】ParallelOptions

    ParallelOptions 构造函数 此构造函数用默认值初始化实例. MaxDegreeOfParallelism 初始化为-1,表示没有对应采用的并行度进行上限设置. CancellationT ...

  10. 【C#基础概念】编程语言:弱类型、强类型、动态类型、静态类型

    一.看图区别编程语言 一般来讲,看第一个图就够了 这图是引用的,有错误,Python是强类型,但是图片中却归为弱类型了. 业界堆静态和动态的区分达到共识. 但是堆强类型和弱类型语言还未达成共识.我个人 ...