【题目泛做】数学(多项式)(Lucas定理)(MTT)

简要题意:

有集合 [ n ] = { 1 , 2 , 3 , … , n } [n]=\{1,2,3,\dots,n\} [n]={1,2,3,,n},定义函数 F ( n , k ) = ∑ S ⊆ [ n ] , ∣ S ∣ = k ∏ x ∈ S x F(n,k)=\sum\limits_{S\subseteq[n],|S|=k}\prod_{x\in S}x F(n,k)=S[n],S=kxSx,求对于 n n n,有多少个 k k k 使得 F ( n , k ) F(n,k) F(n,k) 在模 p p p 下不为 0 0 0 p p p 是质数。

n ≤ 1 e 1000 , p ≤ 1 e 5 n\leq 1e1000,p\leq 1e5 n1e1000,p1e5


集训队作业2018 【取名字太难了】弱化版

题解:

容易发现 F ( n , k ) = F ( n − 1 , k ) + n ∗ F ( n − 1 , k − 1 ) F(n,k)=F(n-1,k)+n*F(n-1,k-1) F(n,k)=F(n1,k)+nF(n1,k1),其分布和 F ( x ) = ∏ i = 1 n ( 1 + n x ) F(x)=\prod_{i=1}^n(1+nx) F(x)=i=1n(1+nx) 的分布相同,于是我们考虑后面那个多项式的系数分布。

首先我们将多项式看作 ∏ i = 1 n ( x + i ) \prod_{i=1}^n(x+i) i=1n(x+i),不难验证这个和上面的系数就是一个 reverse。

a = ⌊ n / p ⌋ , b = n % p a=\lfloor n/p\rfloor,b=n\%p a=n/p,b=n%p

则原多项式可以写为 ( ∑ i = 1 p ( x + i ) ) a ( ∏ i = 1 b ( x + i ) ) (\sum\limits_{i=1}^p(x+i))^a(\prod\limits_{i=1}^b(x+i)) (i=1p(x+i))a(i=1b(x+i))

考虑多项式的根,我们知道 ∏ i = 1 p ( x + i ) = x ( x p − 1 − 1 ) \prod\limits_{i=1}^p(x+i)=x(x^{p-1}-1) i=1p(x+i)=x(xp11)

原多项式等于 x a ( x p − 1 − 1 ) a ∏ i = 1 b ( x + i ) x^a(x^{p-1}-1)^a\prod_{i=1}^b(x+i) xa(xp11)ai=1b(x+i)

x a x^a xa 是整体位移,不管。

如果 b < p − 1 b<p-1 b<p1 ,由于前面所有非零项的指数都是 p − 1 p-1 p1 的倍数,后面的 ∏ \prod 不会相互干扰,不为 0 0 0 的位置数就是前面不为 0 0 0 的位置个数乘上后面不为 0 0 0 的位置个数。

∏ i = 1 b ( x + i ) \prod_{i=1}^b(x+i) i=1b(x+i) 这个东西直接类似斯特林数倍增求一下就行了,最好用 M T T MTT MTT

然后我们需要考虑 ( x p − 1 − 1 ) a (x^{p-1}-1)^a (xp11)a 的非零系数数量。

二项式展开我们发现就是求有多少个 ( a i ) {a\choose i} (ia) 非零,考虑 Lucas 定理,显然只要转化成 p p p 进制后 i i i 每位都比 a a a 小就行了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int MOD=998244353;

int mod;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int po(int a,int b){int r=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(r,a);return r;}
inline void ex_gcd(int a,int b,int&x,int &y){
	if(!b){x=1,y=0;return;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}inline int Inv(int a){int x,y;ex_gcd(mod,a,y,x);return x+(x>>31&mod);}

cs int bit=19,SIZE=1<<bit|7;

namespace MTT{

cs double PI=acos(-1),PI2=PI+PI;
struct cp{
	double x,y;cp(){}
	cp(double _x,double _y):x(_x),y(_y){}
	friend cp operator+(cs cp &a,cs cp &b){return cp(a.x+b.x,a.y+b.y);}
	friend cp operator-(cs cp &a,cs cp &b){return cp(a.x-b.x,a.y-b.y);}
	friend cp operator*(cs cp &a,cs cp &b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
	cp& operator+=(cs cp &b){x+=b.x,y+=b.y;return *this;}
	cp& operator-=(cs cp &b){x-=b.x,y-=b.y;return *this;}
	cp& operator*=(cs cp &b){return *this=*this*b;}
	cp conj()cs{return cp(x,-y);}
};
inline cp omega(int i,int k){
	return cp(cos(PI2*i/k),sin(PI2*i/k));
}

int r[SIZE];cp *w[bit+1];

void init_omega(){
	for(int re i=1;i<=bit;++i)
		w[i]=new cp[1<<(i-1)];
	for(int re d=1;d<=bit;++d){
		cp wn=omega(1,1<<d);
		for(int re i=0;i<(1<<(d-1));++i)
			w[d][i]=(i&31)?w[d][i-1]*wn:omega(i,1<<d);
	}
}

void DFT(cp *A,int l){
	for(int re i=0;i<l;++i)
	if(i<r[i])std::swap(A[i],A[r[i]]);
	for(int re i=1,d=1;i<l;i<<=1,++d)
	for(int re j=0;j<l;j+=i<<1)
	for(int re k=0;k<i;++k){
		cp &t1=A[j+k],&t2=A[i+j+k];
		cp t=t2*w[d][k];t2=t1-t,t1+=t;
	}
}
void init_len(int l){
	for(int re i=1;i<l;++i)
		r[i]=r[i>>1]>>1|((i&1)?l>>1:0);
}
void mul(int *a,int *b,int l,int *c){
	static cp A[SIZE],B[SIZE],C[SIZE],D[SIZE];
	for(int re i=0;i<l;++i){
		A[i]=cp(a[i]&0x7fff,a[i]>>15);
		B[i]=cp(b[i]&0x7fff,b[i]>>15);
	}init_len(l),DFT(A,l),DFT(B,l);
	for(int re i=0;i<l;++i){
		int u=(l-i)&(l-1);
		C[i]=(A[i].conj()+A[u])*cp(.5,0)*B[u];
		D[i]=(A[i].conj()-A[u])*cp(0,.5)*B[u];
	}DFT(C,l);DFT(D,l);
	for(int re i=0;i<l;++i){
		ll x=C[i].x/l+.5,y=(C[i].y+D[i].x)/l+.5,z=D[i].y/l+.5;
		x%=mod,y%=mod,z%=mod;c[i]=(x+(y<<15)%mod+(z<<30)%mod)%mod;
	}
}

}

int fac[SIZE],ifc[SIZE];
int a[SIZE],b[SIZE],c[SIZE],pw[SIZE];
void solve(int len){
	if(len==1){a[1]=1;return;}
	if(len&1){
		solve(len-1);
		for(int re i=len;i;--i)
			a[i]=add(a[i-1],mul(a[i],len-1));
		return ;
	}int l2=len>>1,l=1;pw[0]=1;
	solve(l2);while(l<=len)l<<=1;
	for(int re i=1;i<=l2;++i)
		pw[i]=mul(pw[i-1],l2);
	for(int re i=0;i<=l2;++i)
		c[i]=mul(a[i],fac[i]);
	for(int re i=0;i<=l2;++i)
		b[l2-i]=mul(pw[i],ifc[i]);
	memset(c+l2+1,0,sizeof(int)*(l-l2));
	memset(b+l2+1,0,sizeof(int)*(l-l2));
	MTT::mul(b,c,l,b);
	for(int re i=0;i<=l2;++i)
		b[i]=mul(b[i+l2],ifc[i]);
	memset(b+l2+1,0,sizeof(int)*(l-l2));
	MTT::mul(a,b,l,a);
}


int p;
int calc(int n){
	if(!n)return 1;
	MTT::init_omega();
	for(int re i=fac[0]=1;i<p;++i)
		fac[i]=mul(fac[i-1],i);
	ifc[p-1]=Inv(fac[p-1]);
	for(int re i=p-2;~i;--i)
		ifc[i]=mul(ifc[i+1],i+1);
	solve(n+1);int res=0;
	for(int re i=1;i<=n+1;++i)
		res+=!!a[i];
	return res;
} 

int num[1007],nl;
void get_n(){
	std::string s;std::cin>>s;
	std::cin>>mod;p=mod;
	std::vector<int> vec;
	for(char c:s)vec.push_back(c-'0');
	std::reverse(vec.begin(),vec.end());
	while(!vec.empty()&&vec.back()==0)
		vec.pop_back();
	while(!vec.empty()){
		int nw=0;
		for(int re i=vec.size()-1;~i;--i){
			nw=nw*10+vec[i];
			vec[i]=nw/p;nw%=p;
		}num[++nl]=nw;
		while(!vec.empty()&&vec.back()==0)
			vec.pop_back();
	}if(!nl)++nl;
}

void Main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	get_n();
	if(num[1]==p-1){
		int ps=1;int ans=1;
		while(ps<=nl&&num[ps]==p-1)++ps;
		for(int re i=nl+1;i>=ps;--i)
			ans=((ll)ans*(num[i]+(i==ps)+1))%MOD;
		cout<<ans<<"\n";return;
	}int ans=calc(num[1]);
	for(int re i=2;i<=nl;++i)
		ans=((ll)ans*(num[i]+1))%MOD;
	cout<<ans<<"\n";
}

inline void file(){
#ifdef zxyoi
	freopen("math.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值