1. 程式人生 > >JZOJ5917. 【NOIP2018模擬10.20】moon

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