这是一个句子测试

3
16
2016
0

Contest20160316滚粗记

惯例开坑。

任务栏:

订正了几题?3/3

BZOJ刷题量?306/300

撒花~~~~~~

T1

一棵有根树,选择点u会获得w[u]的收益(w[u]可能为负),若选择了u且u的k[u]个祖先有一个没有被选,需要额外付出p[u]的代价,最大化收益。

题目名称flow已经暴露了一切。。。。(然而我并不会)

首先考虑网络流,若w[u]>0,源连u,流量w[u],ans加上w[u],否则u连汇,流量-w[u]。对于k[u]的限制,将u的k[u]个祖先向n+u连流量为inf的边,n+u连u,流量为p[u],表示要么全选祖先,要么付出代价,跑最小割即可。

发现这样的边数是n2的,主要是树上一段连续的向某个点连inf的边,可以树链剖分然后用类似线段树的形态加边。

T2

有n个按键,按错按键i的概率为p[i]。一段长度为x的连续成功按键得分为:

[tex]f(x)=tan(\frac{x}{n})e^{arcsin(\frac{0.8x}{n})}[/tex]

求得分的期望。

OSU的即视感,然而这个得分函数是什么玩意?

SB出题人表示:可以用一个十五次多项式来逼近f(x)。

然后就可以用dp来推辣!

然而精度误差着实有些惊人。。。

T3

有一棵树,有白点和黑点,每次随机选择一个起点,然后以随机顺序遍历其所有儿子,若所有黑点都遍历完则结束,否则回到父亲,问走过路径的期望长度。

令S[u]为遍历完u的子树的步数,E[u]为在u的子树中结束遍历的步数。

不妨假定:若u的子树中有黑点,则u为黑点。

若枚举顺序确定,显然发现:最后一个黑儿子之前的所有儿子都必须遍历完。

再推广到不确定的情况,若有m个黑儿子,每个黑儿子成为最后一个黑儿子的概率为1/m,每个白儿子出现在最后一个黑儿子之后的概率为1/(m+1)。

那么:

[tex]e[u]=\frac{m}{m+1}\sum_{v\in{whitenode}}s[v]+\frac{m-1}{m}\sum_{v\in{blacknode}}s[v]+exp[/tex]

[tex]exp=\frac{1}{m}\sum_{v\in{blacknode}}e[v][/tex]

对于根不确定的dp,可以任意确定一个根做一次dp,然后再做一次dfs,利用父亲的信息来更新儿子来求得儿子为根的情况。

[Codes]

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=200010;
const int inf=1000000007;
int n,i,j,ans,edgenum,Edgenum,cnt,time;
int Head[M],Vet[M],Next[M],tid[M],pre[M],son[M],Size[M],top[M];
int fa[M],w[M],a[M],b[M],head[M],vet[M*25],next[M*25],size[M*25],dis[M],h[M];
void Addedge(int x,int y){
	Vet[++Edgenum]=y;
	Next[Edgenum]=Head[x];
	Head[x]=Edgenum;
}
void addedge(int x,int y,int z){
	vet[++edgenum]=y;
	next[edgenum]=head[x];
	head[x]=edgenum;
	size[edgenum]=z;
	vet[++edgenum]=x;
	next[edgenum]=head[y];
	head[y]=edgenum;
	size[edgenum]=0;
}
void build(int l,int r,int p){
	cnt=max(cnt,p+2*n+1);
	if (p!=1)addedge(p+2*n+1,(p>>1)+2*n+1,inf);
	if (l==r){addedge(l,p+2*n+1,inf);return;}
	int mid=l+r>>1;
	build(l,mid,p<<1);
	build(mid+1,r,p<<1^1);
}
void update(int x,int y,int l,int r,int p){
	if (x==l&&y==r){
		addedge(p+2*n+1,n+i,inf);
		return;
	}
	int mid=l+r>>1;
	if (y<=mid)update(x,y,l,mid,p<<1);
		else if (x>mid)update(x,y,mid+1,r,p<<1^1);
			else update(x,mid,l,mid,p<<1),update(mid+1,y,mid+1,r,p<<1^1);
}
int bfs(){
	int l=1,r=1;
	for (int i=1;i<=cnt;i++)dis[i]=-1;
	while (l<=r){
		int u=h[l];
		for (int e=head[u];e;e=next[e]){
			int v=vet[e];
			if (size[e]&&dis[v]<0){
				dis[v]=dis[u]+1;
				h[++r]=v;
			}
		}
		l++;
	}
	if (dis[2*n+1]<0)return 0;else return 1;
}
int dfs(int u,int aug){
	if (u==2*n+1)return aug;
	int flow=0;
	for (int e=head[u];e;e=next[e]){
		int v=vet[e];
		if (size[e]&&dis[v]==dis[u]+1){
			int tmp=dfs(v,min(aug-flow,size[e]));
			size[e]-=tmp;
			size[e^1]+=tmp;
			flow+=tmp;
			if (flow==aug)return flow;
		}
	}
	if (!flow)dis[u]=-1;
	return flow;
}
void dfs1(int u){
	Size[u]=1;son[u]=0;
	for (int e=Head[u];e;e=Next[e]){
		int v=Vet[e];
		dfs1(v);
		Size[u]+=Size[v];
		if (!son[u]||Size[v]>Size[son[u]])son[u]=v;
	}
}
void dfs2(int u,int ance){
	tid[u]=++time;pre[time]=u;top[u]=ance;
	if (son[u])dfs2(son[u],ance);
	for (int e=Head[u];e;e=Next[e]){
		int v=Vet[e];
		if (v==son[u])continue;
		dfs2(v,v);
	}
}
int main(){
	edgenum=1;
	scanf("%d",&n);
	for (i=1;i<=n;i++){
		scanf("%d%d%d%d",&fa[i],&w[i],&a[i],&b[i]);
		Addedge(fa[i],i);
	}
	dfs1(1);
	dfs2(1,1);
	for (i=1;i<=n;i++){
		if (w[i]>0)addedge(tid[i],2*n+1,w[i]),ans+=w[i];
			else addedge(0,tid[i],-w[i]);
	}
	build(1,time,1);
	for (i=1;i<=n;i++){
		int x=fa[pre[i]],r=0;
		while (a[pre[i]]){
			if (tid[x]-tid[top[x]]+1>=a[pre[i]])update(tid[x]-a[pre[i]]+1,tid[x],1,n,1),a[pre[i]]=0;
				else update(tid[top[x]],tid[x],1,n,1),a[pre[i]]-=tid[x]-tid[top[x]]+1;
			x=fa[top[x]];
		}
		addedge(n+i,i,b[pre[i]]);
	}
	while (bfs())ans-=dfs(0,inf);
	printf("%d\n",ans);
}
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const double xishu[16]={-4.24979841297e-12,1.00000008983,0.799978648796,0.654614705503,0.403827353614,0.802129354545,-3.93434353775,23.8762214791,-92.5788259887,253.804090672,-491.286508915,670.149961274,-630.033886213,389.181543743,-142.378854835,23.4766536318};
int n,i,j,k;
double a[100010],c[20][20],dp[100010][20],ans;
int main(){
	scanf("%d",&n);
	c[0][0]=1;
	for (i=1;i<=15;i++){
		c[i][0]=c[i-1][0]/n;
		for (j=1;j<i;j++)c[i][j]=c[i-1][j-1]+c[i-1][j]/n;
		c[i][i]=1;
	}
	for (i=1;i<=n;i++)scanf("%lf",&a[i]);
	a[n+1]=1;
	dp[0][0]=1;
	for (i=1;i<=n;i++){
		for (j=0;j<=15;j++){
			for (k=0;k<=j;k++)dp[i][j]+=dp[i-1][k]*c[j][k];
			dp[i][j]*=1-a[i];
			if (!j)dp[i][j]+=a[i];
			ans+=dp[i][j]*a[i+1]*xishu[j];
		}
	}
	ans=ans*n;
	printf("%.6lf\n",ans);
}
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=200010;
int n,m,i,x,y,edgenum,N;
int head[M],vet[M],next[M],Cnt[M],size[M],col[M],B[M],W[M];
long double E[M],V[M],ans;
void addedge(int x,int y){
	vet[++edgenum]=y;
	next[edgenum]=head[x];
	head[x]=edgenum;
}
void dfs(int u,int pre){
	size[u]=0;
	for (int e=head[u];e;e=next[e]){
		int v=vet[e];
		if (v==pre)continue;
		dfs(v,u);
		size[u]+=size[v]+2;
		col[u]+=col[v];
		if (col[v])B[u]+=size[v]+2,E[u]+=V[v]+1,Cnt[u]++;
			else W[u]+=size[v]+2;
	}
	if (Cnt[u])V[u]=B[u]+(1.0/Cnt[u])*(E[u]-B[u])+Cnt[u]/(Cnt[u]+1.0)*W[u];
}
void Dfs(int u,int pre,int flag,long double now){
	int cnt=Cnt[u],b=B[u],w=W[u];
	long double exp=E[u];
	if (flag)b+=N-size[u],exp+=now+1,cnt++;
		else w+=N-size[u];
	if (cnt)ans+=b+(1.0/cnt)*(exp-b)+cnt/(cnt+1.0)*w;
	for (int e=head[u];e;e=next[e]){
		int v=vet[e];
		if (v==pre)continue;
		if (col[v])b-=size[v]+2,exp-=V[v]+1,cnt--;
			else w-=size[v]+2;
		if (cnt)Dfs(v,u,1,b+(1.0/cnt)*(exp-b)+cnt/(cnt+1.0)*w);
			else Dfs(v,u,col[u]-col[v],0);
		if (col[v])b+=size[v]+2,exp+=V[v]+1,cnt++;
			else w+=size[v]+2;
	}
}
int main(){
	scanf("%d",&n);N=n*2-2;
	for (i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		addedge(x,y);
		addedge(y,x);
	}
	scanf("%d",&m);
	for (i=1;i<=m;i++){
		scanf("%d",&x);
		col[x]=1;
	}
	dfs(1,0);
	Dfs(1,0,0,0);
	printf("%.10Lf\n",ans/n);
}
Category: 蒟蒻的滚粗记 | Tags: 网络流 树链剖分 概率与期望 | Read Count: 272

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com