有一个n个数的严格递增序列a
定义一组数为序列a的一个非空子集,也就是说这里面的元素不能重复,也没有顺序之分。
一组数 S S S的权值为 ( − 1 ) ∣ S ∣ + 1 ∏ i ∈ S a i (-1)^{|S|+1}\prod\limits_{i\in S} a_i (−1)∣S∣+1i∈S∏ai
你可以选择若干组数(组与组之间有顺序,一个元素可以同时出现在很多组)作为一个选择方案,这个方案的权值是所有选择的组的权值的乘积。
定义函数 f ( m ) f(m) f(m)为所有满足选的总题数为m的方案的权值和。
可以证明(原题这么说的),存在n个数对 ( b i , c i ) (b_i,c_i) (bi,ci),满足对于任意的m,都有 f ( m ) = ∑ i = 1 n b i c i m f(m)=\sum\limits_{i=1}^{n}b_ic_i^m f(m)=i=1∑nbicim
将 c i c_i ci从小到大排序后,可以证明数对是唯一的
求出这些数对。
n ≤ 100000 n\leq 100000 n≤100000
咋一看无从下手…
感觉它是一道多项式题。
考虑用生成函数来解决
设一组数的一般生成函数为 G ( x ) G(x) G(x), 指数是选的数的数量,系数是权值
令 P ( x ) = ∏ i = 1 n ( 1 − a i x ) P(x)=\prod\limits_{i=1}^{n}(1-a_ix) P(x)=i=1∏n(1−aix)
容易得到 G ( x ) = 1 − P ( x ) G(x)=1-P(x) G(x)=1−P(x)
令 f ( m ) f(m) f(m)的生成函数为 F ( x ) F(x) F(x)
枚举选多少组,也容易得到 F ( x ) = ∑ i > 0 G i ( x ) = 1 1 − G ( x ) = 1 P ( x ) F(x)=\sum\limits_{i>0}G^i(x)={1\over 1-G(x)}={1\over P(x)} F(x)=i>0∑Gi(x)=1−G(x)1=P(x)1
同时又有 F ( x ) = ∑ i ≥ 0 f ( i ) x i = ∑ i ≥ 0 ∑ j = 1 n b j c j i x i F(x)=\sum\limits_{i\geq 0} f(i)x^i=\sum\limits_{i\geq 0}\sum\limits_{j=1}^{n}b_jc_j^ix^i F(x)=i≥0∑f(i)xi=i≥0∑j=1∑nbjcjixi
交换主体
F ( x ) = ∑ i ≥ 0 f ( i ) x i = ∑ j = 1 n b j ∑ i ≥ 0 c j i x i = ∑ j = 1 n b j 1 − c j x F(x)=\sum\limits_{i\geq 0} f(i)x^i=\sum\limits_{j=1}^{n}b_j\sum\limits_{i\geq 0}c_j^ix^i=\sum\limits_{j=1}^{n}{b_j\over 1-c_jx} F(x)=i≥0∑f(i)xi=j=1∑nbji≥0∑cjixi=j=1∑n1−cjxbj
通分,有
F ( x ) = 1 P ( x ) = ∑ j = 1 n b j ∏ k ̸ = j ( 1 − c k x ) ∏ k ( 1 − c k x ) F(x)={1\over P(x)}={\sum\limits_{j=1}^{n}b_j\prod\limits_{k\not =j}(1-c_kx)\over \prod\limits_{k}(1-c_kx)} F(x)=P(x)1=k∏(1−ckx)j=1∑nbjk̸=j∏(1−ckx)
此处可以感受一下,序列c和序列a是完全相同的
为什么呢?
这里有个不太靠谱的证明
考虑反证,假设存在 i , a i ̸ = c i i,a_i\not= c_i i,ai̸=ci
由于这里的生成函数都是形式幂级数,我们不妨令 x = 1 a i x={1\over a_i} x=ai1
那么 P ( x ) = 0 P(x)=0 P(x)=0,由于a互不相同,右边分母总是至少有一项是不能与左边分母约掉的,这样就矛盾了
因此 c i = a i c_i=a_i ci=ai
或者我们用构造的思想,令a与c等价,那么我们总是能够构造出一组解
那么移项,就有 1 = ∑ j = 1 n b j ∏ k ̸ = j ( 1 − a k x ) 1=\sum\limits_{j=1}^{n}b_j\prod\limits_{k\not =j}(1-a_kx) 1=j=1∑nbjk̸=j∏(1−akx)
我们想要把某个bj分离出来
令 x = 1 a j x={1\over a_j} x=aj1,那么除了 b j b_j bj这一个,其他的全部都是0
就有 1 = b j ∏ k ̸ = j ( 1 − a k a j ) 1=b_j\prod\limits_{k\not =j}\left(1-{a_k\over a_j}\right) 1=bjk̸=j∏(1−ajak)
移项再化式子,可得 b j = 1 − a j ∗ 1 a j P ( 1 a j ) b_j={1-a_j*{1\over a_j}\over P\left({1\over a_j}\right)} bj=P(aj1)1−aj∗aj1
上下都是0,可以用洛必达法则
b j = lim x → 1 a j 1 − a j x P ( x ) = lim x → 1 a j − a j P ′ ( x ) = − a j P ′ ( 1 a j ) b_j=\lim\limits_{x\to {1\over a_j}} {1-a_jx\over P(x)}=\lim\limits_{x\to {1\over a_j}} {-a_j\over P'(x)}={-a_j\over P'({1\over a_j})} bj=x→aj1limP(x)1−ajx=x→aj1limP′(x)−aj=P′(aj1)−aj
这样我们只需要求出 P ′ ( x ) P'(x) P′(x)在每个 1 a j 1\over a_j aj1的点值,带入计算即可
多项式函数求导直接每一项左移乘上系数
剩下的就是经典的多项式多点求值了
套模板即可…
总的时间复杂度是 O ( n log 2 n ) O(n\log ^2n) O(nlog2n)的
#include
#include
#include
#include
#include
#include
#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 M 524288
#define mo 1811939329
#define N 100005
#define LL long long
using namespace std;
LL a[M+1],b[M+1],c[M+1],u1[M+1],wg[M+1],u2[M+1],wi[M+1],r[M+1],q[M+1],cf[20],l2[M+1],ny[M+1],a1[20][M+1],ans[N],s1[20][M+1];
int bit[M+1],n,m,fi[20][N+1],le[20][N+1],lf;
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;
}
void prp(int num)
{
fo(i,0,num) wi[i]=wg[i*(M/num)];
fo(i,0,num-1) bit[i]=(bit[i>>1]>>1)|((i&1)<<(l2[num]-1));
}
void NTT(LL *a,bool pd,int num)
{
fo(i,0,num-1) if(i<bit[i]) swap(a[i],a[bit[i]]);
LL w,v;
for(int lim=num>>1,m=2,half=1;m<=num;half=m,lim>>=1,m<<=1)
{
fo(i,0,half-1)
{
w=(!pd)?wi[i*lim]:wi[num-i*lim];
for(int j=i;j<num;j+=m)
{
v=w*a[j+half]%mo;
a[j+half]=(a[j]-v+mo)%mo;
a[j]=(a[j]+v)%mo;
}
}
}
if(pd) fo(i,0,num-1) a[i]=a[i]*ny[num]%mo;
}
void make(int l,LL *a,LL *b)
{
b[0]=ksm(a[0],mo-2);
for(int m=1,t=2,num=4;m<=l;m=t,t=num,num<<=1)
{
prp(num);
fo(i,0,m-1) c[i]=a[i],u2[i]=b[i];
fo(i,m,t-1) c[i]=a[i],u2[i]=b[i]=0;
fo(i,t,num-1) c[i]=u2[i]=b[i]=0;
NTT(c,0,num),NTT(b,0,num);
fo(i,0,num-1) b[i]=b[i]*b[i]%mo*c[i]%mo;
NTT(b,1,num);
fo(i,0,t-1) b[i]=((LL)2*u2[i]-b[i]+mo)%mo;
fo(i,t,num-1) b[i]=0;
}
}
void rev(int num,LL *a,LL *b)
{
fo(i,0,num-1) b[i]=a[num-i-1];
}
void div(int n,int m,LL *a,LL *b,LL *d,LL *r)
{
rev(m,b,r);
fo(i,m,n-m+1) r[i]=0;
make(n-m+1,r,d);
int num=cf[l2[n]]*2;
prp(num),rev(n,a,u2);
fo(i,n-m+1,num-1) d[i]=u2[i]=0;
NTT(d,0,num),NTT(u2,0,num);
fo(i,0,num-1) d[i]=d[i]*u2[i]%mo;
NTT(d,1,num);
fo(i,n-m+1,num-1) d[i]=0;
fo(i,0,(n-m)>>1) swap(d[i],d[n-m-i]);
num=cf[l2[n]],prp(num);
fo(i,0,m-1) r[i]=d[i],u2[i]=b[i];
fo(i,m,num-1) r[i]=d[i],u2[i]=0;
NTT(r,0,num),NTT(u2,0,num);
fo(i,0,num-1) r[i]=r[i]*u2[i]%mo;
NTT(r,1,num);
fo(i,0,m-1) r[i]=(a[i]-r[i]+mo)%mo;
fo(i,m,num-1) r[i]=0;
}
void prd(int t,int l,int r)
{
if(l==r)
{
fi[t][l]=lf+1;
le[t][l]=2;
a1[t][fi[t][l]+1]=-a[l],a1[t][fi[t][l]]=1;
lf+=2;
return;
}
int mid=(l+r)>>1;
prd(t+1,l,mid),prd(t+1,mid+1,r);
}
void prd1(int t,int l,int r)
{
if(l==r)
{
fi[t][l]=lf+1;
le[t][l]=2;
a1[t][fi[t][l]]=mo-ksm(a[l],mo-2),a1[t][fi[t][l]+1]=1;
lf+=2;
return;
}
int mid=(l+r)>>1;
prd1(t+1,l,mid),prd1(t+1,mid+1,r);
}
void doit(int t,int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
doit(t+1,l,mid),doit(t+1,mid+1,r);
fi[t][l]=fi[t+1][l];
int num=cf[l2[le[t+1][l]+le[t+1][mid+1]-1]];
prp(num);
fo(i,0,num-1)
{
u1[i]=(i<le[t+1][l])?a1[t+1][fi[t+1][l]+i]:0;
u2[i]=(i<le[t+1][mid+1])?a1[t+1][fi[t+1][mid+1]+i]:0;
}
NTT(u1,0,num),NTT(u2,0,num);
fo(i,0,num-1) u1[i]=u1[i]*u2[i]%mo;
NTT(u1,1,num);
le[t][l]=le[t+1][l]+le[t+1][mid+1]-1;
fo(i,0,le[t][l]) a1[t][fi[t][l]+i]=u1[i];
}
void query(int t,int l,int r,int n)
{
if(l==r) ans[l]=s1[t][0];
else
{
int mid=(l+r)>>1;
div(n,le[t+1][l],s1[t],a1[t+1]+fi[t+1][l],q,s1[t+1]);
query(t+1,l,mid,le[t+1][l]-1);
div(n,le[t+1][mid+1],s1[t],a1[t+1]+fi[t+1][mid+1],q,s1[t+1]);
query(t+1,mid+1,r,le[t+1][mid+1]-1);
}
}
int main()
{
cf[0]=1;
fo(i,1,19) cf[i]=cf[i-1]<<1,l2[cf[i]]=i;
fod(i,M-1,1) if(!l2[i]) l2[i]=l2[i+1];
ny[1]=1;
fo(i,2,M) ny[i]=(-ny[mo%i]*(LL)(mo/i)%mo+mo)%mo;
wg[0]=1;
LL c=ksm(13,(mo-1)/M);
fo(i,1,M) wg[i]=wg[i-1]*c%mo;
cin>>n;
fo(i,0,n-1) scanf("%lld",&a[i]);
prd(0,0,n-1);
doit(0,0,n-1);
fo(i,fi[0][0],fi[0][0]+le[0][0]-2) s1[0][i-fi[0][0]]=a1[0][i+1]*(LL)(i-fi[0][0]+1)%mo;
memset(fi,0,sizeof(fi));
memset(le,0,sizeof(le));
memset(a1,0,sizeof(a1));
lf=0;
prd1(0,0,n-1);
doit(0,0,n-1);
query(0,0,n-1,le[0][0]-1);
fo(i,0,n-1) printf("%lld %lld\n",(-a[i]*ksm(ans[i],mo-2)%mo+mo)%mo,a[i]);
}