Comet OJ - Contest #2题解

传送门

既然没参加过就没有什么小裙子不小裙子的了……

顺便全是概率期望真是劲啊……

因自过去而至的残响起舞

\(k\)增长非常快,大力模拟一下就行了

int main(){
	scanf("%lld",&x),sum=2;
	if(x==1)return puts("2"),0;
	fp(i,3,19260817){
		sum+=(sum>>1);
		if(sum>x)return printf("%d\n",i),0;
	}
	return 0;
}

她的想法、他的战斗

卖出的期望价格肯定是\(q={L+R\over 2}\)

然后分类讨论,如果\(q\leq l\)收益是\(0\),否则收益为\({(q-p)(p-l)\over r-l}\),上面是个二次函数,分类讨论一下是否能取到最值即可

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
int l,r,li,ri;
inline double sqr(R double x){return x*x;}
int main(){
	cin>>l>>r>>li>>ri;
	if((l<<1)>=li+ri)return puts("0.0000"),0;
	if((li+ri)*0.5-r<=r-l)return printf("%.4lf\n",0.25*sqr((li+ri)*0.5-l)/(r-l)),0;
	return printf("%.4lf\n",(li+ri)*0.5-r),0;
}

言论的阴影里妄想初萌

我们枚举点集,计算这个点集合法的概率,发现这个概率只和集合大小有关,且\(i\)个点的集合合法概率为\(\left({x\over y}\right)^{i(i-1)\over 2}\)

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
int fac[N],ifac[N],n,x,y,p,res,now,tmp;
int main(){
	scanf("%d%d%d",&n,&x,&y),p=mul(x,ksm(y,P-2)),tmp=now=res=1;
	fac[0]=ifac[0]=1;fp(i,1,n)fac[i]=mul(fac[i-1],i);
	ifac[n]=ksm(fac[n],P-2);fd(i,n-1,1)ifac[i]=mul(ifac[i+1],i+1);
	fp(i,1,n)res=add(res,1ll*fac[n]*ifac[i]%P*ifac[n-i]%P*now%P),tmp=mul(tmp,p),now=mul(now,tmp);
	printf("%d\n",res);
	return 0;
}

错综的光影所迷惑的思念是

首先\(S\)是一个点集,而一个点集的所有直径必定有一个共同的中点(这个点可能在点上也可能在边上),那么我们枚举这个中点,如果一个点集的直径为\(p\),那么所有到它的距离为\({p\over 2}\)的点至少得选两个,且这两个属于不同的子树,而到它的距离小于\({p\over 2}\)的点可以随便选不选,直接\(dp\)一下就好了

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2005,P=998244353;
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
struct eg{int v,nx;}e[N<<1];int head[N],tot=1;
inline void Add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int bin[N],sz[N],f[N],g[N],h[N],now[N],deg[N],n,mx;
void clr(int u,int fa,int dep){
	cmax(mx,dep);
	go(u)if(v!=fa)clr(v,u,dep+1);
}
void dfs(int u,int fa,int dep){
	++now[dep];
	go(u)if(v!=fa)dfs(v,u,dep+1);
}
int main(){
//	freopen("testdata.in","r",stdin);
	scanf("%d",&n),bin[0]=1;
	fp(i,1,n)bin[i]=mul(bin[i-1],2);
	for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),Add(u,v),Add(v,u);
	fp(u,1,n){
		fp(i,0,n)sz[i]=0,g[i]=1,h[i]=0;
		go(u){
			mx=0,clr(v,u,1);
			fp(i,0,mx)now[i]=0;
			dfs(v,u,1);
			fp(i,1,mx)sz[i]+=now[i],g[i]=mul(g[i],bin[now[i]]),h[i]=add(h[i],bin[now[i]]-1);
		}
		++sz[0];
		fp(i,1,n)f[i<<1]=add(f[i<<1],mul(bin[sz[i-1]],dec(g[i],h[i]+1))),sz[i]+=sz[i-1];
	}
	for(R int k=2,u,v;k<=tot;k+=2){
		u=e[k].v,v=e[k^1].v;
		fp(i,0,n)sz[i]=0,g[i]=1,h[i]=0;
		for(int T=1;T<=2;swap(u,v),++T){
			mx=0,clr(v,u,1);
			fp(i,0,mx)now[i]=0;
			dfs(v,u,1);
			fp(i,1,mx)sz[i]+=now[i],g[i]=mul(g[i],bin[now[i]]),h[i]=add(h[i],bin[now[i]]-1);
		}
		fp(i,1,n)f[(i<<1)-1]=add(f[(i<<1)-1],mul(bin[sz[i-1]],dec(g[i],h[i]+1))),sz[i]+=sz[i-1];
	}
	fp(i,1,n-1)printf("%d\n",f[i]);
	return 0;
}

情报强者追逐事件

劲啊……

醒了的概率很麻烦我们考虑没醒的概率,那么自己不能醒,别人也不能让它醒。设\(q_i\)表示\(i\)不醒的概率,\(p_i\)表示\(i\)不自己醒的概率,\(s_i\)表示\(i\)不吵醒\(to_i\)的概率,如果\(i\)不在环里,那么\(q_i=p_i\prod\limits_{to_v=i}\left(q_v+(1-q_v)s_v\right)\),直接拓扑排序一下即可

如果是在环里事情就会变得比较辣手了。我们发现环肯定不会有连出去的边,那么就令拓扑排序之后的\(q\)作为环里的点的新的\(p_i\)

将环上的点依次编号为\(1,2,3,...,m\),断掉\((m,1)\)这条边之后换变成了一条链,那么对于这条链进行一次拓扑排序之后,\(q_m\)就是环上的\(m\)对应的\(q_m\)。破环成链,对于每一个都计算就行了。设环的大小为\(s\),这样的复杂度是\(O(s^2)\)

考虑优化,因为最终的\(q_m\)一定是形如\(p_m\times (kx+b)\)的形式,其中\(x\)的值为\(p_{m+1}\),那么我们只要能在计算不同的\(q\)的时候快速维护好\(k\)\(b\)就可以了,只要倒着转移就行了,具体可以看代码

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int K=-1,Z=0;
inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
void print(R int x){
    if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++K]=z[Z],--Z);sr[++K]=' ';
}
const int N=1e5+5,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
int to[N],deg[N],s[N],p[N],ans[N],vis[N],q[N],st[N],bb[N],kk[N],ip[N],is[N],n,top;
void bfs(){
	int h=1,t=0,u,v;
	fp(i,1,n)if(!deg[i])q[++t]=i;
	while(h<=t){
		v=to[u=q[h++]],vis[u]=1,ans[u]=p[u];
		p[v]=mul(p[v],add(p[u],mul(P+1-p[u],s[u])));
		if(!--deg[v])q[++t]=v;
	}
}
int main(){
//	freopen("testdata.in","r",stdin);
//	freopen("testdata.out","w",stdout);
	n=read();
	for(R int i=1,x,y;i<=n;++i)x=read(),y=read(),p[i]=P+1-mul(x,ksm(y,P-2));
	fp(i,1,n)to[i]=read(),++deg[to[i]];
	for(R int i=1,x,y;i<=n;++i)x=read(),y=read(),s[i]=P+1-mul(x,ksm(y,P-2));
	bfs();
	fp(i,1,n)ip[i]=ksm(p[i],P-2),is[i]=ksm(P+1-s[i],P-2);
	fp(i,1,n)if(!vis[i]){
		st[top=1]=i,vis[i]=1;
		for(R int u=to[i];u!=i;vis[u]=1,st[++top]=u,u=to[u]);
		fp(j,1,top)st[top+j]=st[j];
		int k=1,b=0,kk,bb;
		fp(j,top+1,top+top-1){
			k=mul(k,P+1-s[st[j]]),b=mul(b,P+1-s[st[j]]),b=add(b,s[st[j]]),
			k=mul(k,p[st[j+1]]),b=mul(b,p[st[j+1]]);
		}
		fd(j,top,1){
			ans[st[j]]=add(mul(p[st[j+1]],k),b);
			k=mul(k,ip[st[j+top]]),b=mul(b,ip[st[j+top]]);
			b=dec(b,s[st[j+top-1]]),b=mul(b,is[st[j+top-1]]),k=mul(k,is[st[j+top-1]]);
			kk=k,bb=b;
			k=1ll*(P+1-s[st[j]])*p[st[j+1]]%P*kk%P,b=(1ll*s[st[j]]*p[st[j+1]]%P*kk%P+bb)%P;
		}
	}
	fp(i,1,n)print(P+1-ans[i]);
	return Ot(),0;
}

真实无妄她们的人生之路

orz zsy

我们考虑分治,设

\[L(x)=\prod_{i=1}^{n/2}(p_ix+1-p_i)=\sum_{i=0}^{n/2}l_ix^i \]

\[R(x)=\prod_{i=n/2+1}^{n}(p_ix+1-p_i)=\sum_{i=0}^{n-n/2}r_ix^i \]

假设我们需要计算\([1,n/2]\)中的答案,那么最终答案肯定是形如\(\sum_{j=0}^{n/2-1}\sum_{k=0}^{n-n/2}l'_jr_ka_{j+k}\),对于左边的所有\(i\)\(r_k\)都是定值,那么我们可以令\(a_j'=\sum\limits_{k=0}^{n-n/2}r_ka_{j+k}\)然后用\(a_j'\)递归左边。\(a_j'\)是个卷积的形式,可以快速计算

这样的话复杂度就是\(O(n\log^2n)\)

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
char sr[1<<21],z[20];int K=-1,Z=0;
inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
void print(R int x){
    if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++K]=z[Z],--Z);sr[++K]=' ';
}
typedef vector<int> poly;
const int N=(1<<18)+5,P=998244353;
inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
	return res;
}
int r[21][N],rt[2][N],inv[21],lim,d;
inline void init(R int len){lim=1,d=0;while(lim<len)lim<<=1,++d;}
void Pre(){
    fp(d,1,18){
        fp(i,1,(1<<d)-1)r[d][i]=(r[d][i>>1]>>1)|((i&1)<<(d-1));
        inv[d]=ksm(1<<d,P-2);
    }
    for(R int t=(P-1)>>1,i=1,x,y;i<262144;i<<=1,t>>=1){
        x=ksm(3,t),y=ksm(332748118,t),rt[0][i]=rt[1][i]=1;
        fp(k,1,i-1)
            rt[1][i+k]=mul(rt[1][i+k-1],x),
            rt[0][i+k]=mul(rt[0][i+k-1],y);
    }
}
void NTT(int *A,int ty){
    fp(i,0,lim-1)if(i<r[d][i])swap(A[i],A[r[d][i]]);
    R int t;
    for(R int mid=1;mid<lim;mid<<=1)
        for(R int j=0;j<lim;j+=(mid<<1))
            fp(k,0,mid-1)
                A[j+k+mid]=dec(A[j+k],t=mul(rt[ty][mid+k],A[j+k+mid])),
                A[j+k]=add(A[j+k],t);
    if(!ty){
        t=inv[d];
        fp(i,0,lim-1)A[i]=mul(A[i],t);
    }
}
poly Mul(poly &a,poly &b){
	int n=a.size(),m=b.size();poly c(n+m-1);
	if(n+m<233){
		fp(i,0,n-1)fp(j,0,m-1)c[i+j]=add(c[i+j],mul(a[i],b[j]));
		return c;
	}
	static int f[N],g[N];init(n+m);
	fp(i,0,n-1)f[i]=a[i];fp(i,n,lim-1)f[i]=0;
	fp(i,0,m-1)g[i]=b[i];fp(i,m,lim-1)g[i]=0;
	NTT(f,1),NTT(g,1);
	fp(i,0,lim-1)f[i]=mul(f[i],g[i]);
	NTT(f,0);
	fp(i,0,n+m-2)c[i]=f[i];
	return c;
}
poly exmul(poly &a,poly &b){
	reverse(b.begin(),b.end());
	int n=a.size(),m=b.size();
	poly c=Mul(a,b),d(n-m+1);
	fp(i,0,n-m)d[i]=c[i+m-1];
	return d;
}
poly pos[N<<2],ans[N<<2];int n;
void solve(int p,int l,int r){
	if(l==r){
		int v=read();v=mul(v,ksm(read(),P-2));
		pos[p].resize(2),pos[p][0]=P+1-v,pos[p][1]=v;
		return;
	}
	int mid=(l+r)>>1;
	solve(p<<1,l,mid),solve(p<<1|1,mid+1,r);
	pos[p]=Mul(pos[p<<1],pos[p<<1|1]);
}
void calc(int p,int l,int r){
	if(l==r)return print(ans[p][0]),void();
	int mid=(l+r)>>1;
	ans[p<<1]=exmul(ans[p],pos[p<<1|1]);
	ans[p<<1|1]=exmul(ans[p],pos[p<<1]);
	calc(p<<1,l,mid),calc(p<<1|1,mid+1,r);
}
int main(){
//	freopen("testdata.in","r",stdin);
	n=read(),ans[1].resize(n),Pre();
	fp(i,0,n-1)ans[1][i]=read();
	solve(1,1,n),calc(1,1,n);
	return Ot(),0;
}
posted @ 2019-05-13 20:55  bztMinamoto  阅读(358)  评论(0编辑  收藏  举报
Live2D