题解 点

传送门

近乎大模拟

均含圆心=随意-恰好一个含圆心-均不含圆心
将恰好一个含圆心拆成钦定一个含圆心,另一个任意-二倍两个均不含圆心
然后各种拆,大概要处理这么个东西
image
\(s, t\) 是枚举该凸包最靠近圆心的边
然后算贡献就是左边随便选右边全是异色
\(p_1, p_2\)\(s, t\) 的前驱后继
然后发现枚举 \(p_1, p_2\) 贡献就是等比数列求和
可以做到 \(O(n)\)

点击查看代码
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, L;
int x[N];
const ll mod=1e9+7, inv2=(mod+1)>>1;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

namespace force{
	int reach[N], r_reach[N], pw[N], ans, tot;
	struct node{int id, pre, suf, pdis, sdis;}p[N];
	inline int qlen(int x, int y) {return (y-x+n)%n;}
	inline int qdis(int a, int b) {return (x[b]-x[a]+L)%L;}
	void solve() {
		pw[0]=1;
		for (int i=1; i<=n; ++i) pw[i]=(pw[i-1]<<1)%mod;
		for (int i=1; i<=n; ++i) p[i].id=i;
		for (int i=1; i<n; ++i) p[i].sdis=x[i+1]-x[i], p[i].suf=i+1;
		p[n].sdis=x[1]-x[n]+L; p[n].suf=1;
		for (int i=2; i<=n; ++i) p[i].pdis=x[i]-x[i-1], p[i].pre=i-1;
		p[1].pdis=x[1]-x[n]+L; p[1].pre=n;
		int dis=0, j=n;
		for (int i=n; i; --i) {
			if (i==j) j=p[j].pre;
			while (i!=j && 2*qdis(j, i)<L) j=p[j].pre;
			r_reach[i]=p[j].suf;
		}
		// cout<<"  reach: "; for (int i=1; i<=n; ++i) cout<<reach[i]<<' '; cout<<endl;
		// cout<<"r_reach: "; for (int i=1; i<=n; ++i) cout<<r_reach[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) {
			ans=(ans+2)%mod;
			if (i==j) j=p[j].suf;
			while (i!=j && 2*qdis(i, j)<L) j=p[j].suf;
			reach[i]=p[j].pre;
			// cout<<"max: "<<i<<' '<<j<<endl;
			if (i==j) {puts("0"); return ;}
			ans=(ans+pw[qlen(i, j)]-2)%mod;
			if (2*qdis(j, i)<L) ans=(ans-1)%mod, ++tot; //, cout<<"none: "<<j<<' '<<p[i].pre<<endl;
			if (2*qdis(j, p[i].pre)<L) ans=(ans-1)%mod, ++tot; //, cout<<"none: "<<p[i].suf<<' '<<p[i].pre<<endl;
		}
		for (int p1=1; p1<=n; ++p1) {
			int pos=r_reach[p1], s=p[p1].suf, t=reach[s];
			int cnt=max(qlen(s, t)-qlen(s, pos), 0ll);
			ans=(ans-(pw[cnt+1]-cnt-2))%mod;
		}
		for (int p2=1; p2<=n; ++p2) {
			int pos=reach[p2], t=p[p2].pre, s=r_reach[t];
			int cnt=max(qlen(s, t)-qlen(pos, t), 0ll);
			ans=(ans-(pw[cnt+1]-cnt-2))%mod;
		}
		cerr<<"tot: "<<tot<<endl;
		ans=(qpow(2, n)-ans-2)%mod;
		printf("%lld\n", (ans*qpow(inv2, n)%mod+mod)%mod);
	}
}

signed main()
{
	freopen("point.in", "r", stdin);
	freopen("point.out", "w", stdout);

	n=read(); L=read();
	if (n==1) {puts("0"); return 0;}
	for (int i=1; i<=n; ++i) x[i]=read();
	force::solve();

	return 0;
}
posted @ 2022-07-30 08:12  Administrator-09  阅读(3)  评论(0编辑  收藏  举报