JZOJ5917. 【NOIP2018模拟10.20】moon

Description

作为申国的学者,你需要严格遵守三大基本原则:
战争即和平
自由即奴役
无知即力量
你正在对一本书进行审核,其中片段写道:
“少焉,月出于东山之上,徘徊于斗牛之间。白露横江,水光接天。纵一苇之所如,凌万顷之茫然。浩浩乎如冯虚御风,而不知其所止;飘飘乎如遗世独立,羽化而登仙。”
这种行为明显不符合三大原则,比如“纵一苇之所如”中自由的意思已经在新话中杯删除了。
但是你在修改的同时,发现书中夹着一道问题:
酥室等人现在的位置是(x,y),同时还有n个景点,坐标分别为(xi,yi)。
每次移动按照下面的顺序操作:
1、 选择一条直线,要求直线经过现在的位置和至少两个景点(如果现在在某个景点那里,也算一个)如果有多条直线满足要求,等概率选择一条。
2、 在选择的这条直线中,等概率选择一个直线覆盖了的景点移动过去,如果目前在景点上,也有可能停住不动。
酥室会进行若干次询问,第i次询问从一个你选的任意点出发(可以不是景点),然后连续移动mi步,最后到达ti的最大概率是多少。

题解

考虑一个点走到另外一个点的概率,
如果经过这个点x的合法直线有cnt条,
y点所在直线上面有S个,
那么从x走的y的概率就是1/cnt/S
可以知道,从景点走到景点的概率是不变,也就是一个不变的矩阵。
于是可以用矩阵乘法优化。
而最后一步就枚举在哪一条直线。

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <math.h>
#define N 203
#define db double
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
	n=0;
	ch=G();
	while((ch<'0' || ch>'9') && ch!='-')ch=G();
	int w=1;
	if(ch=='-')w=-1,ch=G();
	while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
	n*=w;
}

int gcd(int x,int y){return x%y?gcd(y,x%y):y;}

struct node
{
	int a,b,c;
}line[N*N];

bool cmp(node x,node y)
{
	return x.a<y.a || (x.a==y.a && x.b<y.b) || (x.a==y.a && x.b==y.b && x.c<y.c);
}
db f[15][N][N],g[N],t[N],ans,sum;
int n,x,y,m,a[2][N],v[N],id[N*N],tot,w,z[N],S;
vector<int>q[N*N];

bool is(int i,int j)
{
	return a[0][j]*line[i].a+a[1][j]*line[i].b+line[i].c==0;
}

void add(int i,int j)
{
	line[++tot].a=a[1][i]-a[1][j];
	line[tot].b=a[0][j]-a[0][i];
	line[tot].c=-a[0][i]*line[tot].a-a[1][i]*line[tot].b;
	int g;
	if(line[tot].b==0)g=gcd(abs(line[tot].c),abs(line[tot].a));
		else g=gcd(abs(line[tot].c),gcd(abs(line[tot].a),abs(line[tot].b)));

	line[tot].a=line[tot].a/g;
	line[tot].b=line[tot].b/g;
	line[tot].c=line[tot].c/g;
	if(line[tot].a<0 || (line[tot].a==0 && line[tot].b<0))line[tot].a=-line[tot].a,line[tot].b=-line[tot].b,line[tot].c=-line[tot].c;
}

void mul(int x)
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=n;k++)
				f[x][i][j]=f[x][i][j]+f[x-1][i][k]*f[x-1][k][j];
}

int main()
{
	freopen("moon.in","r",stdin);
	freopen("moon.out","w",stdout);
	
	z[0]=1;
	for(int i=1;i<15;i++)z[i]=z[i-1]<<1;
	
	read(n);
	for(int i=1;i<=n;i++)
	{
		read(a[0][i]);read(a[1][i]);
		for(int j=1;j<i;j++)add(i,j);
	}
	sort(line+1,line+1+tot,cmp);
	for(int i=1;i<=tot;i++)
		if((line[i].a^line[i-1].a) || (line[i].b^line[i-1].b) || (line[i].c^line[i-1].c))
		{
			id[++m]=i;
			for(int j=1;j<=n;j++)
				if(is(i,j))q[m].push_back(j),v[j]++;
		}
	memset(f,0,sizeof(f));
	for(int j=1;j<=n;j++)
		for(int i=1;i<=m;i++)
			if(is(id[i],j))
			{
				S=q[i].size();
				for(int k=0;k<S;k++)f[0][j][q[i][k]]=f[0][j][q[i][k]]+(db)1.0/v[j]/S;
			}
	for(int i=1;i<15;i++)mul(i);
	
	for(read(w);w;w--)
	{
		read(x);read(y);y--;
		memset(g,0,sizeof(g));
		g[x]=1;
		for(int i=0;i<15;i++)
			if(y&z[i])
			{
				memset(t,0,sizeof(t));
				for(int j=1;j<=n;j++)
					for(int k=1;k<=n;k++)
						t[j]=t[j]+g[k]*f[i][j][k];
				memcpy(g,t,sizeof(g));
			}
		ans=0;
		for(int i=1;i<=m;i++)
		{
			S=q[i].size();sum=0;
			for(int j=0;j<S;j++)sum=sum+g[q[i][j]];
			ans=max(ans,sum/S);
		}
		printf("%.10lf\n",(db)ans);
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/83246579