min-max容斥小结

公式及其证明

公式:
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)=TS(1)T1min(T)
min ⁡ ( S ) = ∑ T ⊆ S ( − 1 ) ∣ T ∣ − 1 max ⁡ ( T ) \min(S)=\sum_{T\subseteq S}(-1)^{|T|-1}\max(T) min(S)=TS(1)T1max(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=0n(1)j+11a1<a2...<ajnAa1Aa2...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=0n(1)j1a1<a2...<ajnAa1Aa2...Aaj(2)

我们设 A i = { 1 , 2 , . . . , i } A_i=\{1,2,...,i\} Ai={1,2,...,i}.
定义集族 S ′ S' S,若 x ∈ S x\in S xS,则有 A x ∈ S ′ A_x\in S' AxS.
因为 ∣ 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) AxAy=max(x,y),AxAy=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)=xS Ax=j=1n(1)j+1(k=1jAak)=TS(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)=TS(1)T1min(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=0nk(1)j(jnk)=0nk=[n=k].
所以公式显然成立.

大小翻转 x = − x x=-x x=x可得公式二.

例题

HDU4336

min ⁡ − max ⁡ \min-\max minmax容斥的套路是化 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)=iTpi1,求一个的概率还是很简单的~~

#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)=ST=pS1=1fwt[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+ysonxfy+1.
为了避免后效性,我们定义 f x = A x ⋅ f f a + B x f_x=A_x\cdot f_{fa} + B_x fx=Axffa+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+ysonxAyfx+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=degxAyffa+degxAydegx+ByAx=degxAy1,Bx=degxAydegx+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(q3n)会T,优化一下可以做到 O ( q ⋅ 2 n ⋅ n ) O(q\cdot 2^n \cdot n) O(q2nn).
如果我们全部预处理一般的话,复杂度即为 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 n5e4,ai1e6.

神仙题,膜题解才会.

通过这题 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 minmax容斥的方法连起来.
max ⁡ ( S ) = ∑ T ⊆ S ( − 1 ) ∣ T ∣ + 1 min ⁡ ( T ) \max(S)=\sum_{T\subseteq S} (-1)^{|T|+1} \min(T) max(S)=TS(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)=TSgcd(T)(1)T+1(xSpx).
我们把所有质因子的情况乘起来就是总的情况了:$ 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 \} {fxxS},这里的 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)=TSgcd(fT)(1)T+1=TSfgcd(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=g1g=fμ,fn=dngdgn=dnfdμ(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}} TSfgcd(T)(1)T+1=TS(dgcd(T)gd)(1)T+1=dg(d)dgcd(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=10n=[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+2 bn,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) (n1e6,p1e9+7)

我们可以推一下公式:
a n = a n − 1 + 2 ∗ b n − 1 a_n=a_{n-1}+2*b_{n-1} an=an1+2bn1,
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=an1+bn1=an2+2bn2+bn1=1+bn1+i=1n22bi.
差分得到: 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} bnbn1=bn1+2bn2bn2=bn1+bn2bn=2bn1+bn2.(其实不推也罢)

然后,我们猜个结论 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)=TSgcd(fT)(1)T+1=TSfgcd(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,ab,fi=afi1+bfi2gcd(fx,fy)=fgcd(x,y)

引理1: ∀ i ∈ N , b ⊥ f i \forall i\in \N,b \bot f_i iN,bfi.证明:前两项显然成立,然后 f i ≡ a ∗ f i − 1 ( m o d    b ) f_i\equiv a*f_{i-1} (\mod b) fiafi1(modb),因为 a ⊥ b , f i − 1 ⊥ b a\bot b,f_{i-1}\bot b ab,fi1b,所以可以归纳,结论正确.
引理2: f n ⊥ f n + 1 f_n \bot f_{n+1} fnfn+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,bfn1)=gcd(fn,fn1)...=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=fnfm(n+1)+fn+1fmngcd(fm,fn)=gcd(fn,fn+1fmn)=gcd(fn,fmn).这个可以更相减损,所以可以归纳出 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)=STf(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=0x1f(i+1)(ix1).

由二项式反演得: 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)xi(ix)g(i+1)=(1)x(k1)(k1x) ,即 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)xk(k1x1).

例题
列出公式 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)=TS(1)Tk(k1T1)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 k11,那么我们可以考虑试着把 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=fi1,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)Tk(k1T1)=(1)Tk+1(k1T)(T)=(1)Tk+1[(k1T1)+(k2T1)]=(1)Tk+1(k1T1)+(1)Tk+1(k2T1)=fi1,jp[i],k1fi1,jp[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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值