公式及其证明
公式:
S
,
T
S,T
S,T为两个非空数集.
max
(
S
)
=
∑
T
⊆
S
(
−
1
)
∣
T
∣
−
1
min
(
T
)
\max(S)=\sum_{T\subseteq S} (-1)^{|T|-1} \min(T)
max(S)=T⊆S∑(−1)∣T∣−1min(T)
min
(
S
)
=
∑
T
⊆
S
(
−
1
)
∣
T
∣
−
1
max
(
T
)
\min(S)=\sum_{T\subseteq S}(-1)^{|T|-1}\max(T)
min(S)=T⊆S∑(−1)∣T∣−1max(T)
证明:
方法1:
我们都知道容斥原理:
∣
∪
i
=
1
n
A
i
∣
=
∑
j
=
0
n
(
−
1
)
j
+
1
(
∑
1
≤
a
1
<
a
2
.
.
.
<
a
j
≤
n
∣
A
a
1
∩
A
a
2
.
.
.
∩
A
a
j
∣
)
(1)
|\cup_{i=1}^n A_i| =\sum_{j=0}^n (-1)^{j+1} \left(\sum\limits_{1\le a_1<a_2...<a_j\le n}|A_{a_1}\cap A_{a_2}...\cap A_{a_j} | \right) \tag 1
∣∪i=1nAi∣=j=0∑n(−1)j+1⎝⎛1≤a1<a2...<aj≤n∑∣Aa1∩Aa2...∩Aaj∣⎠⎞(1)
∣
∩
i
=
1
n
A
i
∣
=
∑
j
=
0
n
(
−
1
)
j
(
∑
1
≤
a
1
<
a
2
.
.
.
<
a
j
≤
n
∣
A
a
1
‾
∩
A
a
2
‾
.
.
.
∩
A
a
j
‾
∣
)
(2)
|\cap_{i=1}^n A_i|=\sum_{j=0}^n (-1)^{j} \left( \sum\limits_{1\le a_1<a_2...<a_j\le n}|\overline{A_{a_1}}\cap \overline{A_{a_2}}...\cap \overline{A_{a_j}}| \right) \tag 2
∣∩i=1nAi∣=j=0∑n(−1)j⎝⎛1≤a1<a2...<aj≤n∑∣Aa1∩Aa2...∩Aaj∣⎠⎞(2)
我们设
A
i
=
{
1
,
2
,
.
.
.
,
i
}
A_i=\{1,2,...,i\}
Ai={1,2,...,i}.
定义集族
S
′
S'
S′,若
x
∈
S
x\in S
x∈S,则有
A
x
∈
S
′
A_x\in S'
Ax∈S′.
因为
∣
A
x
∪
A
y
∣
=
max
(
x
,
y
)
,
∣
A
x
∩
A
y
∣
=
min
(
x
,
y
)
|A_x\cup A_y|=\max(x,y),|A_x\cap A_y|=\min(x,y)
∣Ax∪Ay∣=max(x,y),∣Ax∩Ay∣=min(x,y).
所以
max
(
S
)
=
∣
∪
x
∈
S
A
x
∣
=
∑
j
=
1
n
(
−
1
)
j
+
1
(
∑
∣
∩
k
=
1
j
A
a
k
∣
)
=
∑
T
∈
S
(
−
1
)
∣
T
∣
+
1
min
(
T
)
\max(S)=|\cup_{x\in S}~ A_x|=\sum_{j=1}^n (-1)^{j+1} \left( \sum |\cap_{k=1}^j A_{a_k}|\right)=\sum_{T\in S}(-1)^{|T|+1}\min(T)
max(S)=∣∪x∈S Ax∣=∑j=1n(−1)j+1(∑∣∩k=1jAak∣)=∑T∈S(−1)∣T∣+1min(T).
同理,我们把每个数的大小翻转 x = − x x=-x x=−x,那么最大值和最小值就互换了,也就可以得到第二个式子.
方法2:
参考资料
上面的证明有一定的局限性,因为是只能作用于整数域.
max
(
S
)
=
∑
T
∈
S
(
−
1
)
∣
T
∣
−
1
min
(
T
)
\max(S)=\sum_{T\in S} (-1)^{|T|-1} \min(T)
max(S)=∑T∈S(−1)∣T∣−1min(T)
那么第
k
k
k小的数的贡献为
∑
j
=
0
n
−
k
(
−
1
)
j
(
n
−
k
j
)
=
0
n
−
k
=
[
n
=
k
]
\sum_{j=0}^{n-k} (-1)^j \dbinom {n-k} j=0^{n-k}=[n=k]
∑j=0n−k(−1)j(jn−k)=0n−k=[n=k].
所以公式显然成立.
大小翻转 x = − x x=-x x=−x可得公式二.
例题
HDU4336
min − max \min-\max min−max容斥的套路是化 max \max max为 min \min min,因为 min \min min一般更好求.
我们定义
m
a
x
(
S
)
,
m
i
n
(
S
)
max(S),min(S)
max(S),min(S)分别表示取到
S
S
S的最大,最小时间,也就是一个
S
S
S对应一个时间集合.
min
(
T
)
=
1
∑
i
∈
T
p
i
\min(T)=\dfrac 1 {\sum_{i\in T} p_i}
min(T)=∑i∈Tpi1,求一个的概率还是很简单的~~
#include<bits/stdc++.h>
using namespace std;
const int N=22;
int n,g[1<<N];
double ans,f[1<<N];
int main() {
while(~scanf("%d",&n)) {
for(int i=0;i<n;i++) scanf("%lf",&f[1<<i]);
g[0]=-1; ans=0;
for(int i=1;i<(1<<n);i++) {
f[i]=f[i&(i-1)]+f[i&-i];
g[i]=-g[i&(i-1)];
ans += g[i]/f[i];
}
printf("%.8lf\n",ans);
}
return 0;
}
P3175 [HAOI2015]按位或
定义
m
i
n
(
T
)
min(T)
min(T)为取到
T
T
T集合中任意一位的最小时间,
m
a
x
(
S
)
max(S)
max(S)为最大时间.
m
i
n
(
T
)
=
1
∑
S
∩
T
≠
∅
p
S
=
1
1
−
f
w
t
[
T
‾
]
min(T)=\dfrac 1{\sum_{S\cap T\ne \varnothing} p_S}=\dfrac 1 {1-fwt[\overline T]}
min(T)=∑S∩T=∅pS1=1−fwt[T]1
#include<bits/stdc++.h>
using namespace std;
const int N=(1<<20)|10;
const double eps=1e-9;
int n,g[N];
double f[N],ans;
void fwt(double *f) {
for(int k=1;k<n;k*=2)
for(int i=0;i<n;i+=2*k)
for(int j=0;j<k;j++)
f[i+j+k] += f[i+j];
}
int main() {
scanf("%d",&n); n=1<<n;
for(int i=0;i<n;i++) scanf("%lf",&f[i]);
fwt(f); g[0]=-1;
for(int i=1;i<n;i++) {
g[i]=-g[i&(i-1)];
if(fabs(f[i^(n-1)]-1)<eps)
{puts("INF"); return 0;}
ans += g[i]/(1-f[i^(n-1)]);
}
printf("%.10lf\n",ans);
return 0;
}
2542. 「PKUWC2018」随机游走
给定一棵 n n n 个结点的树,你从点 x x x 出发,每次等概率随机选择一条与所在点相邻的边走过去。
有 q q q次询问,每次询问给定一个集合 ,求如果从 x x x出发一直随机游走,直到点集 S S S中所有点都至少经过一次的话,期望游走几步。
特别地,点 x x x(即起点)视为一开始就被经过了一次。
答案对 998244353 取模。
我们对于给定的
S
S
S,定义
f
x
f_x
fx表示
x
x
x到
S
S
S一点的期望时间,则
min
(
S
)
=
f
r
o
o
t
\min(S)=f_{root}
min(S)=froot.
转移方程:
f
x
=
f
f
a
+
∑
y
∈
s
o
n
x
f
y
d
e
g
[
x
]
+
1
f_x=\dfrac{f_{fa} + \sum_{y\in son_x} f_y}{deg[x]} +1
fx=deg[x]ffa+∑y∈sonxfy+1.
为了避免后效性,我们定义
f
x
=
A
x
⋅
f
f
a
+
B
x
f_x=A_x\cdot f_{fa} + B_x
fx=Ax⋅ffa+Bx.
则有:
f
x
=
f
f
a
+
∑
y
∈
s
o
n
x
A
y
⋅
f
x
+
B
y
d
e
g
[
x
]
+
1
f_x=\dfrac{f_{fa} + \sum_{y\in son_x} A_y\cdot f_x+B_y}{deg[x]} + 1
fx=deg[x]ffa+∑y∈sonxAy⋅fx+By+1.
把和
f
(
x
)
f(x)
f(x)有关的系数移动到左边,然后消去系数,得到:
f
x
=
f
f
a
d
e
g
x
−
∑
A
y
+
d
e
g
x
+
∑
B
y
d
e
g
x
−
∑
A
y
→
A
x
=
1
d
e
g
x
−
∑
A
y
,
B
x
=
d
e
g
x
+
∑
B
y
d
e
g
x
−
∑
A
y
f_x=\dfrac{f_{fa}}{deg_x-\sum A_y}+\dfrac{deg_x+\sum B_y}{deg_x-\sum A_y}\rightarrow A_x=\dfrac 1 {deg_x-\sum A_y}, B_x=\dfrac{deg_x+\sum B_y}{deg_x-\sum A_y}
fx=degx−∑Ayffa+degx−∑Aydegx+∑By→Ax=degx−∑Ay1,Bx=degx−∑Aydegx+∑By.
特别的,对于
S
S
S内的点
x
x
x,
f
x
=
A
x
=
B
x
=
0
f_x=A_x=B_x=0
fx=Ax=Bx=0.
然后就是一个子集和的问题了,显然
O
(
q
∗
3
n
)
O(q*3^n)
O(q∗3n)会T,优化一下可以做到
O
(
q
⋅
2
n
⋅
n
)
O(q\cdot 2^n \cdot n)
O(q⋅2n⋅n).
如果我们全部预处理一般的话,复杂度即为
O
(
n
2
n
+
∑
k
)
O(n2^n+\sum k)
O(n2n+∑k).
int n,q,rt,cnt[M],f[M],fa[N];
struct edge{int y,next;} a[N*2]; int len,last[N],deg[N];
void ins(int x,int y) {a[++len]=(edge){y,last[x]}; last[x]=len; deg[x]++;}
struct rec {
ll x,y;
void operator *=(ll t) {x=x*t%mod; y=y*t%mod;}
void operator +=(rec t) {x=(x+t.x)%mod; y=(y+t.y)%mod; }
} ;
ll power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=c*a%mod;
b /= 2; a=a*a%mod;
}
return c;
}
rec dfs(int x,int S) {
rec now=(rec){0,0};
if(S>>x&1) return now;
for(int k=last[x],y;k;k=a[k].next)
if((y=a[k].y)^fa[x]) {
fa[y]=x;
now += dfs(y,S);
}
ll t=power(deg[x]-now.x+mod);
now.x=t; now.y=(now.y+deg[x])*t%mod;
return now;
}
int main() {
qr(n); qr(q); qr(rt); rt--;
for(int i=1,x,y;i<n;i++)
qr(x),qr(y),--x,--y,ins(x,y),ins(y,x);
fa[rt]=cnt[0]=-1;
for(int i=1;i<(1<<n);i++)
cnt[i]=-cnt[i&(i-1)],f[i]=(cnt[i]+mod)*dfs(rt,i).y%mod;
for(int i=1;i<(1<<n);i*=2)
for(int j=i;j<(1<<n);j++) if(j&i) f[j]=(f[j]+f[i^j])%mod;
while(q--) {
int k,x=0,y; qr(k);
while(k--) qr(y),x|=1<<(--y);
pr2(f[x]);
}
return 0;
}
1355 斐波那契的最小公倍数
给定一个长度为 n n n的序列 a a a,求 l c m ( f a 1 , f a 2 , . . . , f a n ) m o d ( 1 0 9 + 7 ) lcm(f_{a_1},f_{a_2},...,f_{a_n})\mod (10^9+7) lcm(fa1,fa2,...,fan)mod(109+7),其中 f f f为斐波那契数列. n ≤ 5 e 4 , a i ≤ 1 e 6 n\le 5e4,a_i\le 1e6 n≤5e4,ai≤1e6.
神仙题,膜题解才会.
通过这题 get 一个斐波那契数列的性质: gcd ( f n , f m ) = f gcd ( n , m ) \gcd(f_n,f_m)=f_{\gcd(n,m)} gcd(fn,fm)=fgcd(n,m).
由于
l
c
m
,
g
c
d
lcm,gcd
lcm,gcd分别是指数的
max
,
min
\max,\min
max,min运算,不妨把他们用
min
−
max
\min-\max
min−max容斥的方法连起来.
max
(
S
)
=
∑
T
⊆
S
(
−
1
)
∣
T
∣
+
1
min
(
T
)
\max(S)=\sum_{T\subseteq S} (-1)^{|T|+1} \min(T)
max(S)=∑T⊆S(−1)∣T∣+1min(T)
对于同一个质因子的话,则有
l
c
m
(
S
)
=
∏
T
⊆
S
gcd
(
T
)
(
−
1
)
∣
T
∣
+
1
(
x
∈
S
→
p
∣
x
)
lcm(S)=\prod_{T\subseteq S} \gcd(T)^{(-1)^{|T|+1}}(x\in S\rightarrow p|x)
lcm(S)=∏T⊆Sgcd(T)(−1)∣T∣+1(x∈S→p∣x).
我们把所有质因子的情况乘起来就是总的情况了:$ lcm(S)=\prod_{T\subseteq S} \gcd(T){(-1){|T|+1}}$.
定义
f
S
f_S
fS表示
{
f
x
∣
x
∈
S
}
\{f_x|x\in S \}
{fx∣x∈S},这里的
S
S
S为
a
a
a.
s
o
a
n
s
=
l
c
m
(
f
S
)
=
∏
T
⊆
S
g
c
d
(
f
T
)
(
−
1
)
∣
T
∣
+
1
=
∏
T
⊆
S
f
g
c
d
(
T
)
(
−
1
)
∣
T
∣
+
1
so~~ans=lcm(f_S)=\prod_{T\subseteq S} gcd(f_T)^{(-1)^{|T|+1}}=\prod_{T\subseteq S} f_{gcd(T)}^{(-1)^{|T|+1}}
so ans=lcm(fS)=∏T⊆Sgcd(fT)(−1)∣T∣+1=∏T⊆Sfgcd(T)(−1)∣T∣+1.
我们不可能枚举
T
,
求
gcd
(
T
)
T,求\gcd(T)
T,求gcd(T),因为这是
2
n
n
2^n n
2nn级别的暴力.
考虑每个位置
d
d
d 的影响, 那么显然我们有一个
∑
[
g
c
d
(
T
)
=
d
]
(
−
1
)
∣
T
∣
+
1
\sum[gcd(T)=d](-1)^{|T|+1}
∑[gcd(T)=d](−1)∣T∣+1 的指数.
有
gcd
\gcd
gcd 我们想到什么,没错就是我们的莫比乌斯反演,不过是在
∏
\prod
∏ 意义下哦.
f
=
g
∗
1
⇔
g
=
f
∗
μ
,
f
n
=
∏
d
∣
n
g
d
⇔
g
n
=
∏
d
∣
n
f
d
μ
(
n
/
d
)
f=g*1\Leftrightarrow g=f*\mu,f_n=\prod_{d|n} g_d\Leftrightarrow g_n=\prod_{d|n} f_d^{\mu(n/d)}
f=g∗1⇔g=f∗μ,fn=∏d∣ngd⇔gn=∏d∣nfdμ(n/d).
加法转乘法可以类比 指数加法 和 乘法 来理解.(不过我们下面并没有用到反演公式)
我们把其他约数的影响去掉即可得到
g
n
g_n
gn.
式子变成这个丫子:
∏
T
⊆
S
f
g
c
d
(
T
)
(
−
1
)
∣
T
∣
+
1
=
∏
T
⊆
S
(
∏
d
∣
g
c
d
(
T
)
g
d
)
(
−
1
)
∣
T
∣
+
1
=
∏
d
g
(
d
)
∑
d
∣
g
c
d
(
T
)
(
−
1
)
∣
T
∣
+
1
\prod_{T\subseteq S} f_{gcd(T)}^{(-1)^{|T|+1}}=\prod_{T\subseteq S} \left( \prod_{d|gcd(T)} g_d \right) ^{(-1)^{|T|+1}}= \prod_d g(d)^{\sum_{d|gcd(T)}(-1)^{|T|+1}}
∏T⊆Sfgcd(T)(−1)∣T∣+1=∏T⊆S(∏d∣gcd(T)gd)(−1)∣T∣+1=∏dg(d)∑d∣gcd(T)(−1)∣T∣+1.
考虑每个
d
d
d的贡献,设
d
d
d的倍数有
n
n
n个,则有:
∑
i
=
1
n
(
n
i
)
(
−
1
)
i
+
1
=
(
∑
i
=
0
n
(
n
i
)
(
−
1
)
i
+
1
)
+
1
=
1
−
0
n
=
[
n
>
0
]
\sum_{i=1}^n \dbinom n i (-1)^{i+1}=\left(\sum_{i=0}^n \dbinom n i (-1)^{i+1} \right) +1=1-0^{n}=[n>0]
∑i=1n(in)(−1)i+1=(∑i=0n(in)(−1)i+1)+1=1−0n=[n>0].
也就是说,只要有一个
d
d
d的倍数,那么
g
d
g_d
gd就会被计算一次.
综上,用个埃氏筛求 g g g并判断倍数有没有即可.总复杂度为 O ( n + m log m ) ( m = max a i ) O(n+m\log m)(m=\max a_i) O(n+mlogm)(m=maxai)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10,mod=1000000007;
int n,g[N],m;
bool v[N];
ll power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=c*a%mod;
b /= 2; a=a*a%mod;
}
return c;
}
void qr(int &x){scanf("%d",&x);}
int main() {
qr(n);
for(int i=1,x;i<=n;i++) qr(x),v[x]=1,m=max(m,x);
g[1]=1; for(int i=2;i<=m;i++) g[i]=(g[i-1]+g[i-2])%mod;
for(int i=1;i*2<=m;i++) {
ll k=power(g[i]);
for(int j=2*i;j<=m;j+=i)
g[j]=g[j]*k%mod;
}
ll ans=1;
for(int i=1;i<=m;i++)
for(int j=i;j<=m;j+=i)
if(v[j]) {ans=ans*g[i]%mod; break;}
printf("%lld\n",ans);return 0;
}
BZOJ #4833. Lydsy1704月赛 最小公倍佩尔数
设 ( 1 + 2 ) n = a n + 2 b n , g n = l c m ( b 1 , b 2 , . . . , b n ) (1+\sqrt 2)^n=a_n+\sqrt 2 b_n,g_n=lcm(b_1,b_2,...,b_n) (1+2)n=an+2bn,gn=lcm(b1,b2,...,bn),求 ∑ i = 1 n i g ( i ) m o d p \sum_{i=1}^n {ig(i)}\mod p ∑i=1nig(i)modp. ( n ≤ 1 e 6 , p ≤ 1 e 9 + 7 ) (n\le 1e6,p\le 1e9+7) (n≤1e6,p≤1e9+7)
我们可以推一下公式:
a
n
=
a
n
−
1
+
2
∗
b
n
−
1
a_n=a_{n-1}+2*b_{n-1}
an=an−1+2∗bn−1,
b
n
=
a
n
−
1
+
b
n
−
1
=
a
n
−
2
+
2
∗
b
n
−
2
+
b
n
−
1
=
1
+
b
n
−
1
+
∑
i
=
1
n
−
2
2
b
i
b_n=a_{n-1}+b_{n-1}=a_{n-2}+2*b_{n-2}+b_{n-1}=1+b_{n-1}+\sum_{i=1}^{n-2}2b_i
bn=an−1+bn−1=an−2+2∗bn−2+bn−1=1+bn−1+∑i=1n−22bi.
差分得到:
b
n
−
b
n
−
1
=
b
n
−
1
+
2
b
n
−
2
−
b
n
−
2
=
b
n
−
1
+
b
n
−
2
→
b
n
=
2
b
n
−
1
+
b
n
−
2
b_n-b_{n-1}=b_{n-1}+2b_{n-2}-b_{n-2}=b_{n-1}+b_{n-2}\rightarrow b_n=2b_{n-1}+b_{n-2}
bn−bn−1=bn−1+2bn−2−bn−2=bn−1+bn−2→bn=2bn−1+bn−2.(其实不推也罢)
然后,我们猜个结论 g c d ( b x , b y ) = b gcd ( x , y ) gcd(b_x,b_y)=b_{\gcd(x,y)} gcd(bx,by)=bgcd(x,y),结果用 _ _ i n t 128 \_\_int128 __int128跑了 n = 100 n=100 n=100范围内,发现结论正确.
那么这道题好像就和上一题没啥区别了:
l
c
m
(
f
S
)
=
∏
T
⊆
S
g
c
d
(
f
T
)
(
−
1
)
∣
T
∣
+
1
=
∏
T
⊆
S
f
gcd
(
T
)
(
−
1
)
∣
T
∣
+
1
.
.
.
=
∏
d
=
1
n
g
i
lcm(f_S)=\prod_{T\subseteq S} gcd(f_T)^{(-1)^{|T|+1}}=\prod_{T\subseteq S}f_{\gcd(T)}^{(-1)^{|T|+1}}...=\prod_{d=1}^n g_i
lcm(fS)=∏T⊆Sgcd(fT)(−1)∣T∣+1=∏T⊆Sfgcd(T)(−1)∣T∣+1...=∏d=1ngi.
我们解出
g
g
g后就差不多做完了…
最后证明一下瞎猜结论的正确性吧:
有个结论,
f
0
=
0
,
f
1
=
1
,
a
⊥
b
,
f
i
=
a
∗
f
i
−
1
+
b
∗
f
i
−
2
→
gcd
(
f
x
,
f
y
)
=
f
gcd
(
x
,
y
)
f_0=0,f_1=1,a\bot b,f_i=a*f_{i-1} + b*f_{i-2} \rightarrow \gcd(f_x,f_y)=f_{\gcd(x,y)}
f0=0,f1=1,a⊥b,fi=a∗fi−1+b∗fi−2→gcd(fx,fy)=fgcd(x,y)
引理1:
∀
i
∈
N
,
b
⊥
f
i
\forall i\in \N,b \bot f_i
∀i∈N,b⊥fi.证明:前两项显然成立,然后
f
i
≡
a
∗
f
i
−
1
(
m
o
d
b
)
f_i\equiv a*f_{i-1} (\mod b)
fi≡a∗fi−1(modb),因为
a
⊥
b
,
f
i
−
1
⊥
b
a\bot b,f_{i-1}\bot b
a⊥b,fi−1⊥b,所以可以归纳,结论正确.
引理2:
f
n
⊥
f
n
+
1
f_n \bot f_{n+1}
fn⊥fn+1,证明:
gcd
(
f
n
,
f
n
+
1
)
=
gcd
(
f
n
,
b
∗
f
n
−
1
)
=
gcd
(
f
n
,
f
n
−
1
)
.
.
.
=
gcd
(
f
1
,
f
2
)
=
1
\gcd(f_n,f_{n+1})=\gcd(f_n,b*f_{n-1})=\gcd(f_n,f_{n-1})...=\gcd(f_1,f_2)=1
gcd(fn,fn+1)=gcd(fn,b∗fn−1)=gcd(fn,fn−1)...=gcd(f1,f2)=1
容易推出 f m = f n ∗ f m − ( n + 1 ) + f n + 1 ∗ f m − n → gcd ( f m , f n ) = gcd ( f n , f n + 1 ∗ f m − n ) = gcd ( f n , f m − n ) f_m=f_n *f_{m-(n+1)} +f_{n+1}*f_{m-n}\rightarrow \gcd(f_m,f_n)=\gcd(f_n,f_{n+1}*f_{m-n} )=\gcd(f_n,f_{m-n}) fm=fn∗fm−(n+1)+fn+1∗fm−n→gcd(fm,fn)=gcd(fn,fn+1∗fm−n)=gcd(fn,fm−n).这个可以更相减损,所以可以归纳出 gcd ( n , m ) \gcd(n,m) gcd(n,m),证毕!
int T,n,mod;
ll power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=c*a%mod;
b /= 2; a=a*a%mod;
}
return c;
}
ll f[N];
int main() {
qr(T); while(T--) {
qr(n); qr(mod);
f[1]=1;
for(int i=2;i<=n;i++) f[i]=(2*f[i-1]+f[i-2])%mod;
for(int i=1;i*2<=n;i++) {
ll t=power(f[i]);
for(int j=i*2;j<=n;j+=i) f[j]=f[j]*t%mod;
}
ll ans=0,s=1;
for(int i=1;i<=n;i++) {
s=s*f[i]%mod;
ans += s*i%mod;
}
pr2(ans%mod);
}
return 0;
}
推广- k t h m a x kthmax kthmax
我们设 k t h m a x ( S ) = ∑ S ⊆ T f ( ∣ T ∣ ) min ( T ) kthmax(S)=\sum_{S\subseteq T} f(|T|) \min(T) kthmax(S)=∑S⊆Tf(∣T∣)min(T).
那么第 x x x 大数的贡献为 [ x = k ] = g ( x ) = ∑ i = 0 x − 1 f ( i + 1 ) ( x − 1 i ) [x=k]=g(x)=\sum_{i=0}^{x-1} f(i+1) \dbinom {x-1} i [x=k]=g(x)=∑i=0x−1f(i+1)(ix−1).
由二项式反演得: f ( x + 1 ) = ∑ i = 0 x ( − 1 ) x − i ( x i ) g ( i + 1 ) = ( − 1 ) x − ( k − 1 ) ( x k − 1 ) f(x+1)=\sum_{i=0}^x (-1)^{x-i} \dbinom x i g(i+1)=(-1)^{x-(k-1)}\dbinom x {k-1} f(x+1)=∑i=0x(−1)x−i(ix)g(i+1)=(−1)x−(k−1)(k−1x) ,即 f ( x ) = ∑ i = 0 x ( − 1 ) x − k ( x − 1 k − 1 ) f(x)=\sum_{i=0}^x (-1)^{x-k} \dbinom {x-1}{k-1} f(x)=∑i=0x(−1)x−k(k−1x−1).
例题
列出公式
k
t
h
max
(
S
)
=
∑
T
⊆
S
(
−
1
)
∣
T
∣
−
k
(
∣
T
∣
−
1
k
−
1
)
min
(
T
)
,
min
(
T
)
=
1
∑
p
kth\max(S)=\sum_{T\subseteq S} (-1)^{|T|-k}\dbinom {|T|-1}{k-1} \min(T),\min(T) =\dfrac 1{\sum p}
kthmax(S)=∑T⊆S(−1)∣T∣−k(k−1∣T∣−1)min(T),min(T)=∑p1.
最暴力的做法为
O
(
2
n
)
O(2^n)
O(2n).
如果我们像背包一样记录
∣
T
∣
,
∑
p
|T|,\sum p
∣T∣,∑p总复杂度为
O
(
n
2
m
)
O(n^2 m)
O(n2m).这样还是会T.
我们发现 k ≤ 11 k\le 11 k≤11,那么我们可以考虑试着把 k k k放进dp的状态内.
定义$f_{i,j,k} 表 示 钦 定 表示钦定 表示钦定k , , ,j=\sum p 时 , 时, 时,\sum (-1)^{|T|-1} \dbinom {|T|-k}{k-1}$ 的大小.
若第
i
i
i 个位置不选有
f
i
,
j
,
k
=
f
i
−
1
,
j
,
k
f_{i,j,k}=f_{i-1,j,k}
fi,j,k=fi−1,j,k.
选择的话,有
f
i
,
j
,
k
=
∑
(
−
1
)
∣
T
∣
−
k
(
∣
T
∣
−
1
k
−
1
)
=
∑
(
−
1
)
∣
T
∣
−
k
+
1
(
∣
T
∣
k
−
1
)
(
∣
T
∣
表
示
前
一
个
状
态
的
大
小
)
=
∑
(
−
1
)
∣
T
∣
−
k
+
1
[
(
∣
T
∣
−
1
k
−
1
)
+
(
∣
T
∣
−
1
k
−
2
)
]
=
∑
(
−
1
)
∣
T
∣
−
k
+
1
(
∣
T
∣
−
1
k
−
1
)
+
(
−
1
)
∣
T
∣
−
k
+
1
(
∣
T
∣
−
1
k
−
2
)
=
f
i
−
1
,
j
−
p
[
i
]
,
k
−
1
−
f
i
−
1
,
j
−
p
[
i
]
,
k
f_{i,j,k}=\sum (-1)^{|T|-k} \dbinom {|T|-1}{k-1}=\sum (-1)^{|T|-k+1}\dbinom{|T|}{k-1}(|T|表示前一个状态的大小)=\sum (-1)^{|T|-k+1}\left[ \dbinom {|T|-1}{k-1}+\dbinom{|T|-1}{k-2}\right]=\sum (-1)^{|T|-k+1} \dbinom {|T|-1}{k-1}+(-1)^{|T|-k+1} \dbinom{|T|-1}{k-2}=f_{i-1,j-p[i],k-1}-f_{i-1,j-p[i],k}
fi,j,k=∑(−1)∣T∣−k(k−1∣T∣−1)=∑(−1)∣T∣−k+1(k−1∣T∣)(∣T∣表示前一个状态的大小)=∑(−1)∣T∣−k+1[(k−1∣T∣−1)+(k−2∣T∣−1)]=∑(−1)∣T∣−k+1(k−1∣T∣−1)+(−1)∣T∣−k+1(k−2∣T∣−1)=fi−1,j−p[i],k−1−fi−1,j−p[i],k.
特别的,边界设定
f
x
,
0
,
0
=
1
f_{x,0,0}=1
fx,0,0=1,这个是为了保证
k
=
1
k=1
k=1时候的正确性~~(其余情况
j
>
0
,
k
=
0
j>0,k=0
j>0,k=0显然为0)
需要注意的是,直接三维会爆空间,需要滚掉
i
i
i维.
#include<bits/stdc++.h>
using namespace std;
const int N=1010,K=12,M=10010,mod=998244353;
typedef long long ll;
int n,k,m,p[N];
ll f[2][M][K],inv[M];
int main(){
scanf("%d%d%d",&n,&k,&m); k=n-k+1;
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
int x=0,y=1; f[x][0][0]=1;
for(int i=1;i<=n;i++) {
swap(x,y); memset(f[x],0,sizeof f[x]),f[x][0][0]=1;
for(int j=1;j<p[i];j++)
for(int v=1;v<=k;v++)
f[x][j][v]=f[y][j][v];
for(int j=p[i];j<=m;j++)
for(int v=1;v<=k;v++)
f[x][j][v]=(f[y][j][v]+f[y][j-p[i]][v-1]-f[y][j-p[i]][v]+mod)%mod;
}
ll ans=0;
inv[1]=1; for(int i=2;i<=m;i++) inv[i]=inv[mod%i]*(mod-mod/i)%mod;
for(int i=1;i<=m;i++) ans += f[x][i][k]*inv[i]%mod;
printf("%lld\n",ans%mod*m%mod); return 0;
}