原谅

题目描述

终其一生,我们在寻找一个原谅。
犯下了太多错,要原谅的那个人,永远都是自己。
Samjia在深夜中望见了没有边界的人生,他没有想到过自己犯下了这么多的错误,他想在他的一生中寻求一个原谅。
他的人生是一个没有边界的平面,平面上有n个错误,每个错误是一个点,每个点i有一定的坐标(x[i],y[i]),有一个参数p 表示每个点有p的概率出现在平面上,注意两个不同的点的出现互相没有影响,Samjia可以在两个点之间连一条线段,两条线段不能在除了端点以外的地方相交,现在Samjia想知道他最多可以连的线段数的期望。
温馨提示:请看最后面的提示:)
本题的答案在mod 100000007意义下计算

结论

容易发现最优一定是三角剖分。
若存在非三角形区域一定还能够继续连边。
设凸包上有k个点,有F个三角形,总共V个点,E条边。
除凸包上的边,每条边都出现在两个三角形中,凸包上点数等于边数。
则有3F+k=2E
根据欧拉定理V+F-E=1
结合两条式子可以得到
3V-k-3=E
现在求E的期望,我们其实要求k的期望,因为V的期望显然是n*p。
凸包上的点的期望等于凸包上的边的期望。
(我们不需要考虑k=1的情况,把它当作0,那么会有3*1-0-3=0,对E无贡献,而这种情况也恰好凸包上是没有边的)
而k=2呢?看起来好像只有1条边,但有两个点!其实如果我们把一条无向边拆成两条有向边,那么k=2没有任何问题。
接下来根据期望的线性性,我们枚举一条有向边,计算其在凸包上的概率。那么先枚举始点,将该点连出的有向边都进行向量的坐标表示,接下来极角排序,按顺序枚举一条有向边。
那么一条有向边要在凸包上,它在另一条有向边的左手方向,那有向边可出现可不出现,但如果它在另一条有向边的右手方向,那必定不出现!
所以可以维护一个指针来快速获得哪个极角区域的点不能出现,就可以计算了。
注意全部点都不出现时,我们的公式失效了,这种情况最后要加回来。

#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn=1000+10,mo=100000007;
db a[maxn][2],c[maxn][2],x,y;
int b[maxn];
int i,j,k,l,t,n,m,p,q,ans,top;
bool cmp(int x,int y){
    return atan2(c[x][1],c[x][0])<atan2(c[y][1],c[y][0]);
}
db cross(db x1,db y1,db x2,db y2){
    return x1*y2-x2*y1;
}
int qsm(int x,int y){
    if (!y) return 1;
    int t=qsm(x,y/2);
    t=(ll)t*t%mo;
    if (y%2) t=(ll)t*x%mo;
    return t;
}
int main(){
    freopen("forgive.in","r",stdin);freopen("forgive.out","w",stdout);
    scanf("%d%d",&n,&p);
    q=((1-p)%mo+mo)%mo;
    fo(i,1,n) scanf("%lf%lf",&a[i][0],&a[i][1]);
    fo(i,1,n){
        fo(j,1,n) c[j][0]=a[j][0]-a[i][0],c[j][1]=a[j][1]-a[i][1];
        top=0;
        fo(j,1,n)
            if (j!=i) b[++top]=j;
        sort(b+1,b+top+1,cmp);
        k=1;l=0;
        fo(j,1,top){
            x=c[b[j]][0];y=c[b[j]][1];
            while (cross(x,y,c[b[k%top+1]][0],c[b[k%top+1]][1])>0&&k%top+1!=j){
                k=k%top+1;
                l++;
            }
            t=n-2-l;
            ans=(ans+(ll)p*p%mo*qsm(q,t)%mo)%mo;
            if (l) l--;else k++;
        }
    }
    ans=(((ll)3*n%mo*p%mo-ans-3)%mo+mo)%mo;
    ans=(ans+(ll)3*qsm(q,n)%mo)%mo;
    printf("%d\n",ans);
}
以下是一个示例的HTML代码,可以用烟花特效显示“姐姐我错啦,原谅我好不好”: ```html <!DOCTYPE html> <html> <head> <title>烟花效果</title> <style type="text/css"> body { background-color: black; } .firework { position: absolute; border-radius: 50%; background-color: #fff; animation: explode 1s ease-out forwards; } @keyframes explode { 0% { transform: scale(0); } 100% { transform: scale(15); opacity: 0; } } .message { position: absolute; font-size: 40px; color: white; left: 50%; top: 50%; transform: translate(-50%, -50%); animation: fade 3s ease-out forwards; } @keyframes fade { 0% { opacity: 0; } 100% { opacity: 1; } } </style> </head> <body> <div class="message">姐姐我错啦,原谅我好不好</div> <script type="text/javascript"> // 创建烟花 function createFirework() { var firework = document.createElement('div'); firework.className = 'firework'; firework.style.left = Math.random() * 100 + '%'; firework.style.top = Math.random() * 100 + '%'; document.body.appendChild(firework); setTimeout(function() { firework.parentNode.removeChild(firework); }, 1000); } // 定时创建烟花 setInterval(createFirework, 500); </script> </body> </html> ``` 这段代码会在页面中央显示一个白色的文字“姐姐我错啦,原谅我好不好”,并且会随机创建白色的烟花特效。可以在样式中调整文字的颜色、大小、位置等属性,也可以在JavaScript中调整烟花的创建间隔、持续时间等参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值