码迷,mamicode.com
首页 > 其他好文 > 详细

SDOI2017 Round1 Day2 题解

时间:2017-04-14 00:12:46      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:++i   sdoi   个人   维护   round   分数   str   down   printf   

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

BZOJ4819 新生舞会

模板题,分数规划+二分图最大权匹配。费用流跑得过,可以不用KM。

#include<bits/stdc++.h>
#define pb push_back
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];
bool spfa(){
	flo c=0;
	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(int i=0;i<h[u].size();++i){
				edge*j=e+h[u][i];
				if(d[u]+j->w>d[j->v]&&j->c){
					d[j->v]=d[u]+j->w;
					p[j->v]=j-e;
					if(!vis[j->v]++)q[++b]=j->v;
				}
			}
		}
		if(d[s2]==-inf)
			return 1;
		int f=inf;
		for(int i=s2;i!=s1;i=e[p[i]^1].v)
			f=min(f,e[p[i]].c);
		c+=f*d[s2];
		if(c<0)return 0;
		for(int i=s2;i!=s1;i=e[p[i]^1].v){
			e[p[i]].c-=f;
			e[p[i]^1].c+=f;
		}
	}
}
int n,a[N][N],b[N][N];
bool jud(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]);
	}
	return spfa();
}
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=1e-4,r=1e4;
	while(r-l>1e-8){
		flo j=(l+r)/2;
		(jud(j)?l:r)=j;
	}
	printf("%.6f\n",l);
}

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);
		}
	}
}

  

SDOI2017 Round1 Day2 题解

标签:++i   sdoi   个人   维护   round   分数   str   down   printf   

原文地址:http://www.cnblogs.com/f321dd/p/6706854.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!