zoukankan      html  css  js  c++  java
  • 【CF989E】A Trance of Nightfall

    题目

    根据题意,只有刚开始所在的点可能不是给定的(n)个点,之后所有的位置一定都在给定的点集中了;我们大力求一下(P_{i,j})表示从点(i)移动到点(j)的概率,这个随便暴力一下就好了,由于询问的终点是给定的,于是我们利用求出来的(P_{i,j})建一张反图

    接下来不妨考虑一下起始点的位置,我们大力猜想这个起始点不可能是两条直线的交点,感性理解一下发现这个结论非常正确;在交点上相当于对各条直线上的答案取了一个加权平均值,这个平均值一定小于答案最大的那条直线,我们把起始点放在那条直线上一定比在交点上更优。

    于是起始点只可能有两种情况,可能是给定点集中的某个点,也可能在给定点集形成的一条直线上且不是任意两条直线的交点;不难发现第二种情况包含第一种情况,我们只需要考虑第二种情况即可。

    由于直线条数不超过(O(n^2))条,于是我们可以暴力每一条直线,并处理出每一条直线上点有哪些。一条直线的答案就是上面每一个点到(t)的概率除以直线上点的个数。

    由于我们建了反图,所以转化成了(t)到上面每一个点的概率,我们现在要求的就是这个东西了;不难发现这是一个简单dp,我们可以通过矩阵来优化这个dp,但是直接上是(O(qn^3log m))的,这看起来不是很科学。

    这就是一个简单的套路了,两个矩阵相乘是(O(n^3))的,但是向量乘矩阵却是(O(n^2))的,我们求出最终的转移矩阵也只是为了和一个向量相乘,所以我们只保留(2)的次幂的矩阵,拿着向量去乘这些矩阵就好了,这样一组询问的复杂度就只有(O(n^2log m))了。

    复杂度是(O(n^3+qn^2log m)),代码

    #include<bits/stdc++.h>
    #define re register
    #define max(a,b) ((a)>(b)?(a):(b))
    const int maxn=205;
    int n,f[maxn],vis[maxn],Q,ma[maxn][maxn],num;
    struct pt{int x,y;}p[maxn];
    struct Mat{double a[maxn][maxn];}pw[14];
    struct Vector{double d[maxn];}ans;
    std::vector<int> line[maxn*maxn];
    inline int operator*(const pt &A,const pt &B) {return A.x*B.y-A.y*B.x;}
    inline pt operator-(const pt &A,const pt &B) {return (pt){A.x-B.x,A.y-B.y};}
    inline Mat operator*(const Mat &A,const Mat &B) {
    	Mat C;
    	for(re int i=1;i<=n;i++)
    		for(re int j=1;j<=n;j++) C.a[i][j]=0;
    	for(re int k=1;k<=n;k++)
    		for(re int i=1;i<=n;i++)
    			for(re int j=1;j<=n;j++) C.a[i][j]+=A.a[i][k]*B.a[k][j];
    	return C;
    }
    inline Vector operator*(const Vector &A,const Mat &B) {
    	Vector C;for(re int i=1;i<=n;i++) C.d[i]=0;
    	for(re int i=1;i<=n;i++) 
    		for(re int j=1;j<=n;j++) C.d[j]+=A.d[i]*B.a[i][j];
    	return C;
    }
    inline void calc(int t,int m) {
    	for(re int i=1;i<=n;i++)ans.d[i]=0;ans.d[t]=1;
    	for(re int i=13;i>=0;--i)if(m>>i&1) ans=ans*pw[i];
    }
    inline void work() {
    	for(re int i=0;i<line[num].size();++i)
    		for(re int j=0;j<line[num].size();++j)ma[line[num][i]][line[num][j]]=1;
    }
    int main() {
    	scanf("%d",&n);
    	for(re int i=1;i<=n;i++)scanf("%d%d",&p[i].x,&p[i].y);
    	for(re int i=1;i<=n;i++) {
    		int Line_num=0;double nw=0;
    		for(re int j=1;j<=n;j++) {
    			if(j==i||vis[j]) continue;
    			int tot=0;++Line_num;
    			for(re int k=1;k<=n;k++)
    				if((p[k]-p[i])*(p[j]-p[i])==0) vis[k]=1,++tot;
    			for(re int k=1;k<=n;++k)
    				if((p[k]-p[i])*(p[j]-p[i])==0) f[k]=tot;
    			nw+=1.0/(double)tot;
    		}
    		double p=1.0/(double)Line_num;
    		for(re int j=1;j<=n;j++) {
    			if(j==i) {pw[0].a[i][i]=nw*p;continue;}
    			pw[0].a[j][i]=1.0/(double)f[j];
    			pw[0].a[j][i]*=p;
    		}
    		for(re int j=1;j<=n;j++)f[j]=vis[j]=0;
    	}
    	for(re int i=1;i<=n;i++) 
    		for(re int j=i+1;j<=n;j++) {
    			if(ma[i][j]) continue;++num;
    			for(re int k=1;k<=n;k++)
    				if((p[i]-p[k])*(p[j]-p[k])==0) line[num].push_back(k);
    			work();
    		}
    	for(re int i=1;i<=13;i++)pw[i]=pw[i-1]*pw[i-1];
    	scanf("%d",&Q);int t,m;double nw;
    	while(Q--) {
    		scanf("%d%d",&t,&m);nw=0;
    		calc(t,m-1);
    		for(re int i=1;i<=num;++i) {
    			double k=0;
    			for(re int j=0;j<line[i].size();++j) k+=ans.d[line[i][j]];
    			k*=1.0/(double)line[i].size();
    			nw=max(k,nw);
    		}
    		printf("%.12lf
    ",nw);
    	}return 0;
    }
    //g++ cf989e.cpp -o cf989e
    
  • 相关阅读:
    UVa 1451 Average (斜率优化)
    POJ 1160 Post Office (四边形不等式优化DP)
    HDU 3507 Print Article (斜率DP)
    LightOJ 1427 Substring Frequency (II) (AC自动机)
    UVa 10245 The Closest Pair Problem (分治)
    POJ 1741 Tree (树分治)
    HDU 3487 Play with Chain (Splay)
    POJ 2828 Buy Tickets (线段树)
    HDU 3723 Delta Wave (高精度+calelan数)
    UVa 1625 Color Length (DP)
  • 原文地址:https://www.cnblogs.com/asuldb/p/12170532.html
Copyright © 2011-2022 走看看