SDOI2017 Round1 Day2 题解

T2好厉害啊……AK不了啦……不过要是SCOI考这套题就好了240保底。

BZOJ4819 新生舞会

模板题,分数规划+二分图最大权匹配。

费用流跑得过,可以不用KM。

UPD:分数规划用迭代跑得飞快。

#include<bits/stdc++.h>
#define pb push_back
#define FOR(i,v)\
	for(typeof(v.end())i=v.begin();i!=v.end();++i)
using namespace std;
typedef double flo;
const int inf=1e9;
const int N=205;
struct edge{
	int v,c;
	flo w;
}e[20400];
vector<int>h[N];
int l;
void ins(int u,int v,int c,flo w){
	edge a={v,c,w};
	h[u].pb(l);
	e[l++]=a;
	edge b={u,0,-w};
	h[v].pb(l);
	e[l++]=b;
}
flo d[N];
int s1,s2,q[N*N],vis[N],p[N];
int n,a[N][N],b[N][N];
flo sol(flo c){
	for(int i=s2;~i;--i)
		h[i].clear();
	l=0;
	for(int i=1;i<=n;++i){
		ins(s1,i,1,0);
		ins(i+n,s2,1,0);
		for(int j=1;j<=n;++j)
			ins(i,j+n,1,a[i][j]-c*b[i][j]);
	}
	while(1){
		fill(d,d+s2+1,-inf);
		d[q[0]=s1]=0;
		for(int a=0,b=0;a<=b;++a){
			int u=q[a];
			vis[u]=0;
			FOR(i,h[u])
				if(d[u]+e[*i].w>d[e[*i].v]&&e[*i].c){
					d[e[*i].v]=d[u]+e[*i].w;
					p[e[*i].v]=*i;
					if(!vis[e[*i].v]++)
						q[++b]=e[*i].v;
				}
		}
		if(d[s2]==-inf)
			break;
		int f=inf;
		for(int i=s2;i!=s1;i=e[p[i]^1].v)
			f=min(f,e[p[i]].c);
		for(int i=s2;i!=s1;i=e[p[i]^1].v){
			e[p[i]].c-=f;
			e[p[i]^1].c+=f;
		}
	}
	flo p=0,q=0;
	for(int u=1;u<=n;++u)
		FOR(i,h[u])
			if(!e[*i].c){
				p+=a[u][e[*i].v-n];
				q+=b[u][e[*i].v-n];
			}
	return p/q;
}
int main(){
	scanf("%d",&n);
	s2=n*2+1;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			scanf("%d",a[i]+j);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			scanf("%d",b[i]+j);
	flo l=1;
	while(1){
		flo j=sol(l);
		if(fabs(j-l)<1e-8)
			return!printf("%.6f\n",j);
		l=j;
	}
}

BZOJ4820 硬币游戏

设$f_i$为经过$i$的次数的期望。把所有非终止态记为一个状态$p$,考虑$p$加上一个人的串,可能直接到对应的终止态,也可能先到其他终止态(可能是自己),因此要减去其他终止态的贡献。比如终止态$x$、$y$的串分别为TTH、HTT,那么$p$+TTH可能是$y$+TH或$y$+H,因此$f_x=\frac18f_p-\frac34f_y$,因为$p$有$\frac18$的概率到$x$,其中到了$y$的话有$\frac34$的概率到$x$。可能先到其他终止态的情况也就是其他串的后缀匹配了当前串的前缀,可以用kmp计算。列出这些方程后高斯消元即可。

#include<bits/stdc++.h>
using std::swap;
typedef long double flo;
const int N=302;
int n,m,f[N];
char z[N][N];
flo c[N][N];
void piv(int i){
	int j=i;
	for(int k=i+1;k<=n;++k)
		if(fabs(c[k][i])>fabs(c[j][i]))j=k;
	for(int k=i;k<=n+1;++k)
		swap(c[i][k],c[j][k]);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i)
		scanf("%s",z[i]);
	f[0]=-1;
	for(int i=0;i<n;++i){
		int j=0,k=-1;
		while(j<m){
			while(~k&&z[i][j]!=z[i][k])k=f[k];
			f[++j]=++k;
		}
		for(int l=0;l<n;++l){
			j=k=0;
			while(j<m){
				while(~k&&z[l][j]!=z[i][k])k=f[k];
				++j,++k;
			}
			for(;k;k=f[k])
				c[i][l]+=pow(.5l,m-k);
		}
		c[i][n]=-pow(.5l,m);
		c[n][i]=1;
	}
	c[n][n+1]=1;
	for(int i=0;i<=n;++i){
		piv(i);
		for(int j=n+1;j>=i;--j)
			c[i][j]/=c[i][i];
		for(int j=0;j<=n;++j)
			if(i!=j)
				for(int k=n+1;k>=i;--k)
					c[j][k]-=c[j][i]*c[i][k];
	}
	for(int i=0;i<n;++i)
		printf("%.10f\n",double(c[i][n+1]));
}

BZOJ4821 相关分析

简单线段树,维护$\sum x$、$\sum y$、$\sum xy$、$\sum x^2$以及两种标记。

#include<cstdio>
#define P (k<<1)
#define S (P^1)
typedef long double flo;
const int N=1e5+5;
flo cal1(flo n){return n*(n-1)/2;}
flo cal2(flo n){return n*(n-1)*(n*2-1)/6;}
struct vec{flo a,b,c,d;};
vec operator+(vec a,vec b){
	vec c={
		a.a+b.a,a.b+b.b,a.c+b.c,a.d+b.d
	};
	return c;
}
struct node{
	int i,j,n;
	vec s;
	flo xd,yd,xc,yc;
	bool d,c;
	void upd1(flo x,flo y){
		if(!d)
			xd=x,yd=y,d=1;
		else
			xd+=x,yd+=y;
		s.c+=y*s.a+x*s.b+n*x*y;
		s.d+=x*s.a*2+n*x*x;
		s.a+=n*x;
		s.b+=n*y;
	}
	void upd2(flo x,flo y){
		xc=x,yc=y,c=1,d=0;
		flo a=x+i,b=y+i;
		s.a=n*a+cal1(n);
		s.b=n*b+cal1(n);
		s.c=n*a*b+cal1(n)*(a+b)+cal2(n);
		s.d=n*a*a+cal1(n)*a*2+cal2(n);
	}
}a[N*4];
void down(int k){
	if(a[k].c){
		a[P].upd2(a[k].xc,a[k].yc);
		a[S].upd2(a[k].xc,a[k].yc);
		a[k].c=0;
	}
	if(a[k].d){
		a[P].upd1(a[k].xd,a[k].yd);
		a[S].upd1(a[k].xd,a[k].yd);
		a[k].d=0;
	}
}
void upd1(int k){
	a[k].s=a[P].s+a[S].s;
}
void upd2(int k){
	a[k].i=a[P].i;
	a[k].j=a[S].j;
	a[k].n=a[P].n+a[S].n;
	upd1(k);
}
int f[N],g[N];
void pre(int i,int j,int k){
	if(i==j){
		flo x=f[i],y=g[i];
		a[k]=(node){i,j,1,x,y,x*y,x*x};
	}else{
		pre(i,i+j>>1,P);
		pre((i+j>>1)+1,j,S);
		upd2(k);
	}
}
void inc(flo x,flo y,int s,int t,int k){
	if(s<=a[k].i&&a[k].j<=t)
		a[k].upd1(x,y);
	else{
		down(k);
		if(s<a[S].i)inc(x,y,s,t,P);
		if(t>a[P].j)inc(x,y,s,t,S);
		upd1(k);
	}
}
void cov(flo x,flo y,int s,int t,int k){
	if(s<=a[k].i&&a[k].j<=t)
		a[k].upd2(x,y);
	else{
		down(k);
		if(s<a[S].i)cov(x,y,s,t,P);
		if(t>a[P].j)cov(x,y,s,t,S);
		upd1(k);
	}
}
vec ask(int s,int t,int k){
	if(s==a[k].i&&a[k].j==t)
		return a[k].s;
	down(k);
	return t<a[S].i?ask(s,t,P):s>a[P].j?ask(s,t,S):ask(s,a[P].j,P)+ask(a[S].i,t,S);
}
int main(){
	int n,m,o,s,t,x,y;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)scanf("%d",f+i);
	for(int i=1;i<=n;++i)scanf("%d",g+i);
	pre(1,n,1);
	while(m--){
		scanf("%d%d%d",&o,&s,&t);
		if(o==1){
			vec v=ask(s,t,1);
			int n=t-s+1;
			printf("%.10f\n",double((v.c-v.a*v.b/n)/(v.d-v.a*v.a/n)));
		}else{
			scanf("%d%d",&x,&y);
			(o==2?inc:cov)(x,y,s,t,1);
		}
	}
}
posted @ 2017-04-13 23:49  f321dd  阅读(196)  评论(0编辑  收藏  举报