学了几天,总算是把loj这个题做出来了。。
随便开了一套题。。然后第一题就不会实在是太没有面子了
有挺多前置知识的
我的学习资料
两个题的题意基本都是一样的
只不过第一个比较简单,可以视为完全没有限制
第二个的话则是有限制的
很显然,第二个是第一个的加强版。。
当然两题都可以用第二个的做法来做
其实
从推导的难度来说,第二个做法简单一些
从知识的要求来说,第一个做法简单一些
首先,当然是先构造生成函数
1
+
x
+
x
a
i
+
x
2
a
2
+
.
.
.
.
.
+
x
a
i
∗
(
b
i
+
1
)
1+x+x^{a_i}+x^{2a_2}+.....+x^{ai*(bi+1)}
1+x+xai+x2a2+.....+xai∗(bi+1)
最最暴力的方法就是直接一个一个式子NTT起来,那么复杂度就是
n
m
l
o
g
m
nmlogm
nmlogm的
乘起来不好做,于是考虑加起来
乘法什么时候可以变为加法呢?当然就是取对数的时候!
于是我们设一个函数
g
(
x
)
=
l
n
(
f
(
x
)
)
g(x)=ln(f(x))
g(x)=ln(f(x))
第一个的话,
b
i
b_i
bi可以看做是无限
因此,可以写成
1
1
−
x
\frac{1}{1-x}
1−x1
根据这个特殊的性质,我们可以对
g
g
g进行求导
可以得到
g
′
=
f
′
(
x
)
f
(
x
)
=
(
1
−
x
)
(
∑
j
∗
a
i
∗
x
j
∗
a
i
−
1
)
g'=\frac{f'(x)}{f(x)}=(1-x)(\sum{j*a_i*x^{j*a_i-1}})
g′=f(x)f′(x)=(1−x)(∑j∗ai∗xj∗ai−1)
把式子展开,可以得到
g
′
=
∑
a
i
∗
a
j
∗
a
i
−
1
g'=\sum{a_i*a^{j*a_i-1}}
g′=∑ai∗aj∗ai−1
再对
g
′
g'
g′进行积分,就可以得到
g
=
∑
a
i
j
∗
a
i
x
j
∗
a
i
=
∑
1
j
x
j
∗
a
i
g=\sum{\frac{a_i}{j*a_i}x^{j*a_i}}=\sum{\frac{1}{j}x^{j*a_i}}
g=∑j∗aiaixj∗ai=∑j1xj∗ai
容易发现,对于
a
i
a_i
ai一样的,可以放在一起枚举倍数来对系数贡献
那么这个复杂度就是
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)的
g求和以后,再EXP回去就好了
至于第二个,不可以写成
1
1
−
x
\frac{1}{1-x}
1−x1的形式,于是积分完之后似乎没有上一个那么顺利,那么就只可以另辟捷径了,其实这个更简单一些
可以发现,他的式子是
1
−
x
a
i
∗
(
b
i
+
1
)
1
−
x
\frac{1-x^{a_i*(b_i+1)}}{1-x}
1−x1−xai∗(bi+1)
那么
g
(
x
)
=
l
n
(
1
−
x
a
i
∗
(
b
i
+
1
)
)
−
l
n
(
1
−
x
)
g(x)=ln(1-x^{a_i*(b_i+1)})-ln(1-x)
g(x)=ln(1−xai∗(bi+1))−ln(1−x)
根据泰勒展开公式
l
n
(
1
−
x
)
=
−
x
−
x
2
2
−
x
3
3
−
−
x
4
4
−
.
.
.
.
.
.
.
.
ln(1-x)=-x-\frac{x^2}{2}-\frac{x^3}{3}--\frac{x^4}{4}-........
ln(1−x)=−x−2x2−3x3−−4x4−........
然后换元
l
n
(
1
−
x
k
)
=
−
x
−
x
2
k
2
−
x
3
k
3
−
−
x
4
k
4
−
.
.
.
.
.
.
.
.
ln(1-x^k)=-x-\frac{x^{2k}}{2}-\frac{x^{3k}}{3}--\frac{x^{4k}}{4}-........
ln(1−xk)=−x−2x2k−3x3k−−4x4k−........
然后也是一样的枚举倍数就好了
最后EXP回去就行了
这里给出第二个代码
其实两个代码都差不多。。除了枚举倍数有一点点不同以外,剩下的都是板子问题
我们数学老师说,解析几何的秘诀就是一次算对
同样的,多项式的秘诀就是一次打对。。因为我根本不知道怎么调
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const LL N=100005*4;
const LL MOD=998244353,GG=3,GGI=332748118;
LL n,m;
LL t[N];
LL F[N],G[N];
LL A[N],B[N],C[N],D[N],E[N];
LL inv[N];
LL Pow (LL x,LL y)
{
if (y==1) return x;
LL lalal=Pow(x,y>>1);
lalal=lalal*lalal%MOD;
if (y&1) lalal=lalal*x%MOD;
return lalal;
}
LL bin[N];
void NTT (LL *a,LL n,LL o)
{
for (LL u=0;u<n;u++) bin[u]=(bin[u>>1]>>1)|((u&1)*(n>>1));
for (LL u=0;u<n;u++)
if (u<bin[u])
swap(a[u],a[bin[u]]);
for (LL u=1;u<n;u<<=1)
{
LL w,wn=Pow(o==1?GG:GGI,(MOD-1)/(u<<1)),t;
for (LL i=0;i<n;i=i+(u<<1))
{
w=1;
for (LL j=0;j<u;j++)
{
t=w*a[u+i+j]%MOD;
a[u+i+j]=(a[i+j]-t+MOD)%MOD;
a[i+j]=(a[i+j]+t)%MOD;
w=w*wn%MOD;
}
}
}
if (o==-1)
{
LL Inv=Pow(n,MOD-2);
for (LL u=0;u<n;u++) a[u]=a[u]*Inv%MOD;
}
}
LL tmp[N];
void get_inv (LL *f,LL *g,LL n)
{
if (n==1) {g[0]=Pow(f[0],MOD-2);return ;}
get_inv(f,g,n>>1);
LL nn=n<<1;
for (LL u=0;u<n;u++) tmp[u]=f[u];
for (LL u=n;u<nn;u++) g[u]=tmp[u]=0;
NTT(g,nn,1);NTT(tmp,nn,1);
for (LL u=0;u<nn;u++) g[u]=((2-g[u]*tmp[u]%MOD)*g[u]%MOD+MOD)%MOD;
NTT(g,nn,-1);for (LL u=n;u<nn;u++) g[u]=0;
}
void dao (LL *f,LL *g,LL n) {for (LL u=1;u<n;u++) g[u-1]=f[u]*u%MOD;g[n-1]=0;}
void jifen (LL *f,LL *g,LL n) {for (LL u=1;u<n;u++) g[u]=f[u-1]*Pow(u,MOD-2);g[0]=0;}
void get_ln (LL *f,LL *g,LL n)
{
dao(f,A,n);get_inv(f,B,n);
LL nn=n<<1;
NTT(A,nn,1);NTT(B,nn,1);
for (LL u=0;u<nn;u++) A[u]=A[u]*B[u]%MOD;
NTT(A,nn,-1);jifen(A,g,n);
}
void get_EXP (LL *f,LL *g,LL n)
{
if (n==1) {g[0]=1;return ;}
get_EXP(f,g,n>>1);
LL nn=n<<1;
for (LL u=0;u<n;u++) D[u]=g[u];
get_ln(g,E,n);
for (LL u=0;u<n;u++) C[u]=(f[u]+MOD-E[u])%MOD;C[0]++;
for (LL u=n;u<nn;u++) C[u]=D[u]=0;
NTT(C,nn,1);NTT(D,nn,1);
for (LL u=0;u<nn;u++) C[u]=C[u]*D[u]%MOD;
NTT(C,nn,-1);
for (LL u=0;u<n;u++) g[u]=C[u];
}
int main()
{
scanf("%lld%lld",&n,&m);
inv[1]=1;for (LL u=2;u<=n;u++) inv[u]=(MOD-MOD/u)*inv[MOD%u]%MOD;
// printf("%lld\n",5*inv[5]%MOD);
for (LL u=1;u<=m;u++)
{
LL a,b;
scanf("%lld%lld",&a,&b);
if (a>n) continue;
t[a]++;if (b>0&&a*(b+1)<=n) t[a*(b+1)]--;
}
for (LL u=1;u<=n;u++)
{
if (t[u]<0)t[u]=t[u]+MOD;
for (LL i=1;i*u<=n;i++)
F[i*u]=(F[i*u]+t[u]*inv[i]%MOD)%MOD;
}
/*scanf("%lld",&n);
for (int u=0;u<n;u++) scanf("%lld",&F[u]);*/
LL nn=1;while (nn<=n) nn<<=1;
get_EXP(F,G,nn);
for (LL u=1;u<=n;u++) printf("%lld\n",G[u]);
return 0;
}