SDOI2017 Round1 Day2 题解

Posted f321dd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOI2017 Round1 Day2 题解相关的知识,希望对你有一定的参考价值。

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 题解的主要内容,如果未能解决你的问题,请参考以下文章

SDOI2017 R2 Day2

[SDOI2016 Round1] 数字配对

Cogs 2221. [SDOI2016 Round1] 数字配对

搜索(四分树):BZOJ 4513 [SDOI2016 Round1] 储能表

NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记

[SDOI2016Round1]解题报告