JZOJ-senior-5917. 【NOIP2018模拟10.20】moon

2023-11-03 01:31

本文主要是介绍JZOJ-senior-5917. 【NOIP2018模拟10.20】moon,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Time Limits: 2000 ms Memory Limits: 524288 KB

Description

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

Input

第一行一个整数n。
接下来n行每行两个整数,表示xi,yi。
接下来一行一个整数m,表示询问数。
接下来m行每行两个整数ti,mi,表示询问。

Output

对于每个询问输出一行,表示最大的概率,与标准答案误差在10^-6以内就算正确。

Sample Input

5
0 0
1 3
2 2
3 1
4 4
10
1 1
2 1
3 1
4 1
5 1
3 2
3 3
3 4
3 5
3 6

Sample Output

0.50000000000000000000
0.50000000000000000000
0.33333333333333331483
0.50000000000000000000
0.50000000000000000000
0.18518518518518517491
0.15226337448559670862
0.14494741655235482414
0.14332164812274550414
0.14296036624949901017

Data Constraint

在这里插入图片描述

Solution

p [ i ] [ j ] p[i][j] p[i][j] 为从 i i i 走一步到 j j j 的概率
所有经过 i i i 的直线有 c n t cnt cnt 条,其中,经过 j j j 的那条直线上有 n u m num num 个景点
那么 p [ i ] [ j ] = 1 / c n t / n u m p[i][j]=1/cnt/num p[i][j]=1/cnt/num

a [ x ] [ i ] [ j ] a[x][i][j] a[x][i][j] i i i x x x 步到 j j j 的概率
那么 a [ x ] [ i ] [ j ] = ∑ k = 1 n a [ x − 1 ] [ i ] [ k ] ∗ p [ k ] [ j ] a[x][i][j]=\sum^{n}_{k=1}a[x-1][i][k]*p[k][j] a[x][i][j]=k=1na[x1][i][k]p[k][j]

如果每次询问都这么DP,那每次求解的复杂度为 O ( m i ∗ n 3 ) O(mi*n^3) Omin3),不能通过此题

于是我们考虑优化这个求答案的过程

观察发现矩阵 a [ x ] a[x] a[x] 的转化总是用 a [ x − 1 ] a[x-1] a[x1] 的矩阵乘上概率矩阵 p p p 得到,既然每次乘上的矩阵都相同,那我们可以使用矩阵乘法,先预处理出 l o g log log 个矩阵,详见代码中的 F [ k ] . a [ i ] [ j ] F[k].a[i][j] F[k].a[i][j] (表示从 i i i 出发走 2 k 2^k 2k 步到 j j j 的概率),这样的话,对于每次询问,就是一个 1 ∗ n 1*n 1n 的矩阵(这个矩阵我们设为 g g g g [ t ] = 1 g[t]=1 g[t]=1)和 l o g log log n ∗ n n*n nn 的矩阵相乘,利用这种方法,我们倒着做,先求出从终点走 m − 1 m-1 m1 步到每个景点的概率(因为起点不一定在景点上,所以第一步不可以这么做),再处理第一步

对于第一步,它一定在某两点连成的直线上,但不在两直线的交点上
为什么呢?我们尝试这样理解
设起点为 S S S ,平面内有两条直线 L 1 L1 L1 L 2 L2 L2
直线上点的概率和以及总点数分别为 s 1 , s 2 s1,s2 s1s2 c 1 , c 2 c1,c2 c1c2
从起点到终点的概率为 P 2 , P 2 P2,P2 P2P2
S S S 在直线 L 1 L1 L1 上且不在交点上,则 P 1 = s 1 / c 1 P1=s1/c1 P1=s1/c1
S S S 在直线 L 2 L2 L2 上且不在交点上,则 P 2 = s 2 / c 2 P2=s2/c2 P2=s2/c2
S S S 在交点上,则 P 3 = 1 / 2 ∗ ( s 1 / c 1 + s 2 / c 2 ) P3=1/2*(s1/c1+s2/c2) P3=1/2(s1/c1+s2/c2)
这样求出来的 P 3 P3 P3 一定小于等于 s 1 / c 1 s1/c1 s1/c1 或者 s 2 / c 2 s2/c2 s2/c2
换句话说就是不在交点上比在交点上的概率要大啦

Code

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define db doubleusing namespace std;const int N=210,M=1e4+5,inf=2147483647;
int n,m,en,cs,num,tot_k,_2[15];
db g[N],g1[N];
set<int> point[N*N];
set<int>::iterator it;
struct wz{int x,y;}pos[N];
struct matrix{db a[N][N];}F[15];
struct line{db k; int id;}K[N];
struct straight{db k,b;int x,y;}xl[N*N];bool cmp(line x,line y)
{return x.k<y.k||x.k==y.k&&x.id<y.id;
}bool cmq(straight x,straight y)
{return x.k<y.k||x.k==y.k&&x.b<y.b;
}matrix mul(matrix A,matrix B)
{matrix C;memset(C.a,0,sizeof(C.a));fo(i,1,n)fo(j,1,n)fo(k,1,n)C.a[i][j]+=A.a[i][k]*B.a[k][j];return C;
}int main()
{freopen("moon.in","r",stdin);freopen("moon.out","w",stdout);_2[0]=1;fo(i,1,14) _2[i]=_2[i-1]<<1;scanf("%d",&n);fo(i,1,n) scanf("%d%d",&pos[i].x,&pos[i].y);fo(i,1,n){int tot=0;fo(j,1,n) if(j!=i){int yy=pos[i].y-pos[j].y,xx=pos[i].x-pos[j].x;if(pos[i].x!=pos[j].x) K[++tot].k=(db)yy/xx;else K[++tot].k=inf;K[tot].id=j;xl[++tot_k]=(straight){K[tot].k,pos[i].y-K[tot].k*pos[i].x,i,j};}sort(K+1,K+1+tot,cmp);int cnt=0; K[n].k=-inf;fo(j,1,tot) if(K[j].k!=K[j+1].k) ++cnt;int lst=1;fo(j,1,tot) if(K[j].k!=K[j+1].k){int num=j-lst+1; ++num;F[0].a[i][i]+=1.0/cnt/num;fo(k,lst,j) F[0].a[i][K[k].id]=1.0/cnt/num;lst=j+1;}}fo(i,1,14) F[i]=mul(F[i-1],F[i-1]);sort(xl+1,xl+1+tot_k,cmq);xl[tot_k+1]=(straight){-inf,0,0};int lst=1,at=0;fo(i,1,tot_k) if(xl[i].k!=xl[i+1].k||xl[i].b!=xl[i+1].b){++at;fo(j,lst,i) point[at].insert(xl[j].x),point[at].insert(xl[j].y);lst=i+1;}scanf("%d",&m);fo(o,1,m){scanf("%d%d",&en,&cs),--cs;memset(g,0,sizeof(g));g[en]=1; fo(i,0,14) if(cs&_2[i]){memset(g1,0,sizeof(g1));fo(j,1,n)fo(k,1,n)g1[j]+=g[k]*F[i].a[j][k];memcpy(g,g1,sizeof(g));}db ans=0;fo(i,1,at){db sum=0;for(it=point[i].begin();it!=point[i].end();it++) sum+=g[*it];ans=max(ans,sum/point[i].size());}printf("%.10lf\n",ans);}
}

这篇关于JZOJ-senior-5917. 【NOIP2018模拟10.20】moon的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/334643

相关文章

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

hdu4431麻将模拟

给13张牌。问增加哪些牌可以胡牌。 胡牌有以下几种情况: 1、一个对子 + 4组 3个相同的牌或者顺子。 2、7个不同的对子。 3、13幺 贪心的思想: 对于某张牌>=3个,先减去3个相同,再组合顺子。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOExcepti

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

【算法专场】模拟(下)

目录 前言 38. 外观数列 算法分析 算法思路 算法代码 1419. 数青蛙 算法分析 算法思路 算法代码  2671. 频率跟踪器 算法分析 算法思路 算法代码 前言 在前面我们已经讲解了什么是模拟算法,这篇主要是讲解在leetcode上遇到的一些模拟题目~ 38. 外观数列 算法分析 这道题其实就是要将连续且相同的字符替换成字符重复的次数+

模拟实现vector中的常见接口

insert void insert(iterator pos, const T& x){if (_finish == _endofstorage){int n = pos - _start;size_t newcapacity = capacity() == 0 ? 2 : capacity() * 2;reserve(newcapacity);pos = _start + n;//防止迭代

PHP实现二叉树遍历(非递归方式,栈模拟实现)

二叉树定义是这样的:一棵非空的二叉树由根结点及左、右子树这三个基本部分组成,根据节点的访问位置不同有三种遍历方式: ① NLR:前序遍历(PreorderTraversal亦称(先序遍历)) ——访问结点的操作发生在遍历其左右子树之前。 ② LNR:中序遍历(InorderTraversal) ——访问结点的操作发生在遍历其左右子树之中(间)。 ③ LRN:后序遍历(PostorderT

1 模拟——67. 二进制求和

1 模拟 67. 二进制求和 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1:输入:a = "11", b = "1"输出:"100"示例 2:输入:a = "1010", b = "1011"输出:"10101" 算法设计 可以从低位到高位(从后向前)计算,用一个变量carry记录进位,如果有字符没处理完或者有进位,则循环处理。两个字符串对

AMAZING AUCTION(简单模拟)

AMAZING AUCTION 时间限制: 3000 ms  |  内存限制: 65535 KB 难度:4 描述 Recently the auction house hasintroduced a new type of auction, the lowest price auction. In this new system,people compete for the lo