时间限制:2 秒 / 内存限制:1024 MiB

得分: 700 分

问题描述

你被给定整数 L,K 和一个长度为 N 的非负整数序列 A=(A1​,A2​,…,AN​) 。这里, 2K<L 和 0≤A1​<A2​<⋯<AN​<L 是保证的。

考虑一个周长为 L 的圆。取圆上的任意一点作为参考点,从该点沿顺时针方向移动距离 x 到达的点称为坐标为 x 的点。此外,对于每个 i ( 1≤iN ),考虑连接坐标为 Ai​ 的点和坐标为 Ai​+K 的点的弦,并称该弦为 i 。

对于一组弦 s ,分数由以下程序确定:

  • 绘制所有包含在 s 中的弦。绘制的弦将圆分成几个区域;用白色和黑色进行着色。首先,将包含圆心的区域着色为白色,并将剩余区域着色为不同颜色(即相邻区域,通过正长度的线段连接,具有不同的颜色)。可以证明,这种着色方法总是唯一存在的。分数是着色为黑色的区域的数量。

存在 2N 种可能的组合方式针对 s 。计算所有这些组合的得分之和,并对 998244353 取模。

约束条件

  • 1≤K
  • 2K<L≤109
  • 1≤N≤250000
  • 0≤A1​<A2​<⋯<AN​<L
  • 所有输入值都是整数。

输入

输入从标准输入中按以下格式给出:

L K N
A1​ A2​ … AN
《A - 回文数》《A - 回文数》《A - 回文数》

输出

输出答案。


示例输入 1 

复制
5 2 2
0 1

示例输出 1 

复制
4
  • 当未选择任何和弦时,得分为 0 。
  • 当选择和弦 1 时,得分为 1 。
  • 当选择和弦 2 时,得分为 1 。
  • 当选择和弦 1,2 时,得分为 2 。

因此,答案是 4 ,这是这些的和。


样本输入 2 

复制
3 1 1
2

样本输出 2 

复制
1

示例输入 3

复制
5 2 5
0 1 2 3 4

Sample Output 3

复制
80

示例输入 4

复制
7 3 3
0 2 3

示例输出 4

复制
12

思路

设一个端点的两个线段不交叉。

考虑任意黑色区域。

当该区域包含一段弧时,我们为该弧的每个端点分配权重 1/2 。当该区域不包含弧时,该区域有一个唯一且距离圆心最远的顶点。我们为该点分配权重 1 。

关注一个端点,它两边必有一色区域,而它有1/2的概率使用,所以,它的的权重的期望是1/4。

关注两条任意弦的交点,首先,选中两条弦的概率为1/4,如果没有任何其他弦将圆心与这个交点隔开,概率为0,它的的权重的期望是0,否则,权重为 1 的概率为 1/2,它的的权重的期望是1/8。

若有x个交点,y为满足 i 的ai+k<=a[i+1]的数量。这里我们设a[n+i]=a[i]+l 。

没有其他弦将它们与圆心分开的交点数是n-y。

所以,总的期望值为

n/2+x/8-n/8+y/8。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long l,k,n,a[550005],b[250005],s[250005],mod=998244353,lk=0;
long long pow2(long long a1,long long b1,long long m1){
    long long kk1=1;
    while(b1>=1){
        if(b1%2==1){
            kk1*=a1;
        }
        b1/=2;
        a1*=a1;
        kk1%=m1;
        a1%=m1;
    }
    return kk1;
}
int main(){
	cin>>l>>k>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		a[i+n]=a[i]+l;
		b[i]=a[i]+k;
	}
	for(int i=1;i<=n;i++){
		long long l=1,r=2*n,md=2*n;
		while(l<=r){
			long long mid=(l+r)/2;
			if(a[mid]>=a[i]+k){
				md=min(md,mid);
				r=mid-1;
			}
			else{
				l=mid+1;
			}
		}
		md-=i;
		//cout<<md<<endl;
		s[md]++;
	}	
	for(int i=2;i<=n;i++){
		lk=(lk+((i-1)*((s[i]*pow2(2,n-3,mod))%mod))%mod)%mod;
	}
	lk=(lk+(s[1]*pow2(2,n-3,mod))%mod)%mod;
	lk=(lk+n*pow2(2,n-1,mod))%mod;
	lk=((lk-n*pow2(2,n-3,mod))%mod+mod)%mod;
	//lk=(lk+n*pow2(2,n-3,mod)*3)%mod;
	//lk=(lk+s[0]*pow2(2,n-3,mod)*3)%mod;
	cout<<lk<<endl;
	return 0;
}

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐