JZOJ5917. 【NOIP2018模擬10.20】moon
阿新 • • 發佈:2018-11-03
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; }