2019雅礼集训day8 题解

神仙场
T2全场最高17分
坐看大佬全员200

T1 Union

在这里插入图片描述
答案对 1 0 9 + 7 10^9+7 109+7取模。
n ≤ 20 , C i , j &lt; 1 0 9 + 7 n\leq 20,C_{i,j}&lt;10^9+7 n20,Ci,j<109+7

f ( s ) f(s) f(s)表示点集 s s s所构成无向连通图的方案数, g ( s ) g(s) g(s)表示点集 s s s所构成的所有图的方案数(可不连通)。

g ( s ) = ∏ u , v ∈ s , u ≠ v ( C u , v + 1 ) g(s)=\prod\limits_{u,v\in s,u\neq v}(C_{u,v}+1) g(s)=u,vs,u̸=v(Cu,v+1)

考虑枚举 s s s中标号最小的点 x x x的连通块集合 t t t

g ( s ) = ∑ x ∈ t , t ⊆ s f ( t ) g ( s − t ) g(s)=\sum\limits_{x\in t,t\subseteq s}f(t)g(s-t) g(s)=xt,tsf(t)g(st)

设全集为 a l l all all g ′ ( s ) = g ( s ) × [ 1 ∉ s ] g&#x27;(s)=g(s)\times[1\notin s] g(s)=g(s)×[1/s],则 g ( a l l ) = ∑ t ⊆ a l l f ( t ) g ′ ( a l l − t ) g(all)=\sum\limits_{t\subseteq all}f(t)g&#x27;(all-t) g(all)=tallf(t)g(allt),在子集卷积意义下,即为 g = f ∗ g ′ → f = g ∗ ( g ′ ) − 1 g=f*g&#x27;\to f=g*(g&#x27;)^{-1} g=fgf=g(g)1。做一个子集卷积意义下的除法即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=(1<<20)+10,mod=1e9+7;

int n,S,sz[N],h[N],v[N],id[N],tmp[21],inv[21];
int f[21][N],g[21][N],c[21][21];

inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void dc(int &x,int y){x-=y;if(x<0) x+=mod;}

inline void fmt(int *e,int pr)
{
	for(int j,i=1;i<S;i<<=1)
	 for(j=1;j<S;++j) if(j&i)
	  pr?ad(e[j],e[j^i]):dc(e[j],e[j^i]);
}

int main(){
	freopen("union.in","r",stdin);
	freopen("union.out","w",stdout);
	int i,j,k;
	scanf("%d",&n);S=1<<n;
	for(i=0;i<n;++i)
	 for(j=i+1;j<n;++j){
	 	scanf("%d",&c[i][j]);
	 	c[j][i]=c[i][j];
	 }
	for(i=0;i<n;++i) id[1<<i]=i;
	f[0][0]=g[0][0]=v[0]=1;
	for(i=1;i<S;++i){
		sz[i]=sz[i>>1]+(i&1);j=id[i&(-i)];
		v[i]=v[i^(i&(-i))];
		for(k=0;k<n;++k) if((j^k)&&((i>>k)&1))
		 v[i]=(ll)v[i]*(c[j][k]+1)%mod;
		f[sz[i]][i]=v[i];
		if(!(i&1)) g[sz[i]][i]=v[i];
	}
	for(i=0;i<=n;++i) fmt(f[i],1),fmt(g[i],1);
	for(i=0;i<S;++i){
		memset(tmp,0,sizeof(tmp));tmp[0]=1;
	    for(j=0;j<=n;++j){
	    	inv[j]=tmp[j];
	    	for(k=1;j+k<=n;++k)
	    	 dc(tmp[j+k],(ll)inv[j]*g[k][i]%mod);
	    }
	    for(j=0;j<=n;++j) g[j][i]=inv[j];
	}
	for(j=0;j<=n;++j)
	 for(i=0;i<S;++i)
	  ad(h[i],(ll)f[j][i]*g[n-j][i]%mod);
	fmt(h,0);
	printf("%d",h[S-1]);
	return 0;
}

T2 Power

在这里插入图片描述
n ≤ 50 , 1 ≤ k ≤ 1 0 6 , ∣ a ∣ ≤ 1 0 5 , − 2000 ≤ l i ≤ r i ≤ 2000 n\leq 50,1\leq k\leq10^6,|a|\leq 10^5,-2000\leq l_i\leq r_i\leq 2000 n50,1k106,a105,2000liri2000

神仙题,实现也很神仙。

首先考虑 k k k的奇偶性,按 ∑ x i \sum x_i xi的值域分段讨论:

  • k k k为奇,考虑 ( − ∞ , a ] , ( a , + ∞ ) (-\infty,a],(a,+\infty) (,a],(a,+)
  • k k k为偶,考虑 ( − ∞ , − ∣ a ∣ ] , ( − ∣ a ∣ , ∣ a ∣ ] , ( ∣ a ∣ , + ∞ ) (-\infty,-|a|],(-|a|,|a|],(|a|,+\infty) (,a],(a,a],(a,+)

需要求解的是 ∑ x i \sum x_i xi落在某个区间的概率,假设所有变量是在 [ 0 , + ∞ ) [0,+\infty) [0,+)上均匀随机的( [ l i , r i ] [l_i,r_i] [li,ri]的限制容斥一下即可)。

p n ( s ) p_n(s) pn(s)表示 n n n个随机变量之和不超过 s s s的概率(更准确来说时 ∑ x i &lt; = s \sum x_i&lt;=s xi<=s的点在 n n n维空间中所占体积), n &gt; 0 n&gt;0 n>0时考虑枚举最后一个变量的取值:
p n ( x ) = ∫ 0 s p n − 1 ( x ) d x p_n(x)=\int_{0}^sp_{n-1}(x){\rm d}x pn(x)=0spn1(x)dx

p 0 = 1 p_0=1 p0=1递推得到:

p n = x n n ! p_n=\dfrac{x^n}{n!} pn=n!xn

那么 n n n个随机变量之和恰好等于 s s s的概率 q n ( x ) q_n(x) qn(x)即为 p n − 1 ( x ) p_{n-1}(x) pn1(x)

考虑 [ l i , r i ] [l_i,r_i] [li,ri]的容斥,每个随机变量用 s i + x s_i+x si+x的形式表示,设其中 s i = l i s_i=l_i si=li
则区间 ∑ x i = [ l , r ] \sum x_i=[l,r] xi=[l,r]的贡献为:

(1) ∫ l r q n ( x − ∑ s i ) m a x ( x k , a k ) d x \int _{l}^rq_n(x-\sum s_i)max(x^k,a^k){\rm d}x\tag 1 lrqn(xsi)max(xk,ak)dx(1)

注意对于上式,求上界为 + ∞ +\infty +的积分会出问题,考虑转而将每个随机变量用 s i − x s_i-x six的形式表示,设其中 s i = l i s_i=l_i si=li,则区间 ∑ x i = [ l , r ] \sum x_i=[l,r] xi=[l,r]的贡献为:
(2) ∫ l r q n ( ∑ s i − x ) m a x ( x k , a k ) d x \int _{l}^r q_n(\sum s_i-x)max(x^k,a^k){\rm d}x\tag 2 lrqn(six)max(xk,ak)dx(2)

积分二项式定理展开后得到:

  • x ≤ a x\leq a xa a k ( p n ( r − ∑ s i ) − p n ( l − ∑ s i ) ) a^k(p_n(r-\sum s_i)-p_n(l-\sum s_i)) ak(pn(rsi)pn(lsi))
  • x &gt; a x&gt;a x>a 1 ( n − 1 ) ! ∑ i = 0 n − 1 ( − 1 ) i ( n − 1 i ) x i + k + 1 ( ∑ s i ) n − i − 1 1 i + k + 1 \frac{1}{(n-1)!}\sum \limits_{i=0}^{n-1}(-1)^i\binom{n-1}{i}x^{i+k+1}(\sum s_i)^{n-i-1}\frac{1}{i+k+1} (n1)!1i=0n1(1)i(in1)xi+k+1(si)ni1i+k+11

( 1 ) (1) (1)式求 [ ∑ s i , a ] [\sum s_i,a] [si,a]区间的答案,用 ( 2 ) (2) (2)式求 [ a i , ∑ s i ] [a_i,\sum s_i] [ai,si]的答案,就解决了上下界问题。

容斥的过程相当于,将其中某些 s i s_i si设为 r i r_i ri来保证不合法。所以可以将初始的 S S S设为 ∑ l i \sum l_i li,每改变一个 s i s_i si相当于将 S + = l e n i S+=len_i S+=leni。而 ∑ l e n i \sum len_i leni在题中已保证 ≤ 4000 × 50 \leq 4000\times 50 4000×50,做一个 ∑ l e n i \sum len_i leni大小的 01 01 01背包来求出 S + x S+x S+x时的系数。初始化 S + 0 S+0 S+0的系数为1。

需要特判所有 l i = r i l_i=r_i li=ri的情况。

最后答案除以 ∏ i = 1 , l i ≠ r i n ( r i − l i ) \prod \limits_{i=1,l_i\neq r_i}^n(r_i-l_i) i=1,li̸=rin(rili)即可。

#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
typedef long long ll;

int n,K,a,sum,frc[55],nv[55],f[200005],sl,sr,s,ans;
struct le{int l,r;}p[55];

inline int fp(int x,int y)
{
    int re=1;x%=mod;if(x<0) x+=mod;
    for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) re=(ll)re*x%mod;
    return re;
}

inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void dc(int &x,int y){x-=y;if(x<0) x+=mod;}
inline int dci(int x,int y){x-=y;return x<0?x+mod:x;}

inline int binom(int n,int m){
    if(m>n) return 0;if(n==m || m==0) return 1;
    return (ll)frc[n]*nv[m]%mod*(ll)nv[n-m]%mod;
}

inline int cal(int s,int x)
{
    int i,j,re=0;x%=mod;if(x<0) x+=mod;
    for(i=0;i<n;++i){
        j=(ll)binom(n-1,i)*fp(x,i+K+1)%mod*(ll)fp(s,n-1-i)%mod*(ll)fp(i+K+1,mod-2)%mod;
        (i&1)?dc(re,j):ad(re,j);
    }
    return (ll)re*nv[n-1]%mod;
}

int main(){
    int i,j,k;frc[0]=frc[1]=nv[0]=nv[1]=1;
    scanf("%d%d%d",&n,&K,&a);
    for(i=1;i<=n;++i) {
        scanf("%d%d",&p[i].l,&p[i].r);
        sl+=p[i].l;sr+=p[i].r;
        if(p[i].l==p[i].r) i--,n--;else sum+=(p[i].r-p[i].l);
    }
    if(!n) {printf("%d",(K&1)?fp(max(sl,a),K):fp(max(abs(sl),abs(a)),K));return 0;}
    for(i=2;i<=n;++i) 
      frc[i]=(ll)frc[i-1]*i%mod,
      nv[i]=(ll)(mod-mod/i)*nv[mod%i]%mod;
    for(i=2;i<=n;++i) nv[i]=(ll)nv[i]*nv[i-1]%mod;
    f[0]=1;
    for(i=1;i<=n;++i){
       k=p[i].r-p[i].l;
       for(j=sum-k;j>=0;--j)
         dc(f[j+k],f[j]);
    }
    for(i=0;i<=sum;++i) if(f[i]){
         if((s=sr-i)>a) ad(ans,(ll)f[i]*dci(cal(s,s),cal(s,a))%mod);
		 if((s=sl+i)<a) ad(ans,(ll)f[i]*fp(a,K)%mod*(ll)fp(a-s,n)%mod*(ll)nv[n]%mod);
		 if(s<-a && (!(K&1))){
		 	dc(ans,(ll)f[i]*fp(a,K)%mod*(ll)fp(-a-s,n)%mod*(ll)nv[n]%mod);
		 	ad(ans,(ll)f[i]*dci(cal(-s,-s),cal(-s,a))%mod);
		 }
    }
    for(i=1;i<=n;++i) ans=(ll)ans*fp(p[i].r-p[i].l,mod-2);
    printf("%d",ans);
    return 0;

}

T3 Traffic

在这里插入图片描述
n ≤ 1 0 5 n\leq 10^5 n105

对于每个点,显然是从最大的连通块中选一颗子树接到最小的连通块上,所以先 d f s dfs dfs一遍求出删去每个点后的最大,次大,最小连通块。

二分答案转成区间存在性问题,树状数组以 s i z e size size为下标维护 d f s dfs dfs序区间内 s i z e size size在范围内的个数。
注意根到当前点 x x x路径上的所有点 s i z e size size需要 − = s i z e x -=size_x =sizex,另用一个 B I T BIT BIT特殊判断即可。

#include<bits/stdc++.h>
#define mid (l+r>>1)
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;

int n,bit[N],f[N],sz[N],df[N],dfn,L,R;
int head[N],to[N],nxt[N],tot,ans[N];
vector<int>tre[N];

char cp;
inline void rd(int &x)
{
	cp=getchar();x=0;
	for(;!isdigit(cp);cp=getchar());
	for(;isdigit(cp);cp=getchar()) x=x*10+(cp^48);
}

inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}

struct P{
	int mn,mx,id,smx;
	P(){mn=inf;mx=smx=-inf;}
	inline void ins(int u,int v)
	{
		mn=min(mn,u);
		if(u>=mx) {smx=mx;mx=u;id=v;}
		else if(u>smx) smx=u;
	}
}p[N];

void dfs(int x)
{
	sz[x]=1;df[x]=++dfn;
	for(int j,i=head[x];i;i=nxt[i]){
	    j=to[i];dfs(j);sz[x]+=sz[j];
	    p[x].ins(sz[j],j);
	}
	if(x>1) p[x].ins(n-sz[x],f[x]);
}

inline void modify(int x,int v)
{for(;x<=n;x+=(x&(-x))) bit[x]+=v;}

inline int fd(int x)
{return upper_bound(tre[x].begin(),tre[x].end(),R)-lower_bound(tre[x].begin(),tre[x].end(),L);}

void cal(int x)
{
	int i,j;ans[x]=p[x].mx;
	if(p[x].mx>p[x].smx && head[x]){
		int sl,sr,l=max(p[x].smx,(p[x].mx+p[x].mn-1)/2+1),r=p[x].mx-1;
		for(;l<=r;){
			j=0;sl=p[x].mx-mid-1;sr=mid-p[x].mn;
			if(p[x].id==f[x]){
			    L=df[x],R=L+sz[x]-1;
				for(i=sr;i>0;i-=(i&(-i))) j+=(tre[i].size()-fd(i)-bit[i]);
				for(i=sl;i>0;i-=(i&(-i))) j-=(tre[i].size()-fd(i)-bit[i]);
				for(i=min(sr+sz[x],n);i>0;i-=(i&(-i))) j+=bit[i];
				for(i=min(sl+sz[x],n);i>0;i-=(i&(-i))) j-=bit[i];
			}else{
				L=df[p[x].id];R=L+sz[p[x].id]-1;
				for(i=sr;i>0;i-=(i&(-i))) j+=fd(i);
				for(i=sl;i>0;i-=(i&(-i))) j-=fd(i);
			}
			j>0?(r=(ans[x]=mid)-1):(l=mid+1);
		}
	}
	modify(sz[x],1);for(i=head[x];i;i=nxt[i]) cal(to[i]);modify(sz[x],-1);
}

int main(){
    int i,j;
    rd(n);if(n==1) {puts("0");return 0;}
    for(i=2;i<=n;++i){rd(f[i]);lk(f[i],i);}
    dfs(1);
    for(i=1;i<=n;++i)
     for(j=sz[i];j<=n;j+=(j&(-j)))
      tre[j].push_back(df[i]);
    for(i=1;i<=n;++i) sort(tre[i].begin(),tre[i].end());
    cal(1);
    for(i=1;i<=n;++i) printf("%d\n",ans[i]);
    return 0;
} 

小结

T1的子集枚举没想出来不应该啊。
T2忘了怎么求 x n x^n xn的积分是真的zz。
T3没有做出来不可原谅。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值