题目链接:https://atcoder.jp/contests/agc073/tasks/agc073_a
参考出题人题解
首先理解题意可以破圆为链,直接枚举肯定会超时,考虑将转化成期望,对于某一段黑色区域,当某区域包含一段弧时,我们给每个端点加上 \(\frac{1}{2}\) 的权值,当该区域不包含弧时,该区域存在一个距离圆心最远的唯一点,我们给该点加上 \(1\) 的权值,显然,对于一段弧来说,选中它的概率为 \(\frac{1}{2}\),并且对于一个弧来说,它附近的两个区域肯定是一黑一白,因此端点权重的期望为 \(\frac{1}{4}\)。对于两条弦的交点,首先,这两条弦都被选用的概率为 \(\frac{1}{4}\),其次,若不存在其他弦将圆心与该交点隔开,则该交点对应的区域始终为白色,权重恒为 \(0\)。反之,若存在一条或多条这样的弦,则有 \(\frac{1}{2}\) 的概率分配1的权重。综上,当无其他弦将交点与圆心隔开,期望值则为 \(0\),反之则为 \(\frac{1}{8}\)。
计算总端点权值:每条弦有两个端点,每个端点的期望是 \(\frac{1}{4}\),因此总期望为 \(\frac{N}{2}\),但是对于两条的交点我们需要额外考虑,我们需要把端点带来的贡献先去掉。
假设共有 \(I\)个交点,显然所有交点的贡献便是 \(\frac{1}{8}I\)。对于没有交点的两弦来说,定义 \(V=\) 满足 \(Ai+k<=A_{i+1}\) 的 \(i\) 的数量,那么无其他弦将其与圆心隔开的交点数量为 \(N-V\),剩下的 \(I-(N-V)\) 个交点有其他弦将其与圆心隔开。因此总交点期望便是 \((I-N+V)*\frac{1}{8}=\frac{1}{8}I-\frac{1}{8}N+\frac{1}{8}V\)。
综上,总期望是 \(E=\frac{3}{8}N+\frac{1}{8}I+\frac{1}{8}V\),有 \(2^N\) 种可能,因此最后答案再乘以 \(2^N\) 即可。
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4e5 + 10, mod = 998244353;
int a[N], l, k, n;
int ksm(int x, int y)
{int res = 1;while(y){if(y & 1) res = res * x % mod;x = x * x % mod;y >>= 1;}return res;
}
signed main()
{ios::sync_with_stdio(false);cin.tie(nullptr);int V = 0, I = 0;cin >> l >> k >> n;for(int i = 0; i < n; i++) cin >> a[i];for (int i = 0; i < n; i++) {int val = (i == n - 1) ? a[0] + l : a[i + 1];if (a[i] + k <= val) V++;}// int j = 0;// for(int i = 0; i < n; i++)// {// while(j < n && a[j] <= a[i]) j++;// int h = j;// while(h < n && a[h] < a[i] + k) h++;// I += (h - j);// if(a[i] + k >= l)// {// int pos = a[i] + k - l;// int s = 0;// while(s < n && a[s] < pos)s++;// I += s;// } // } // 双指针被卡了for(int i = 0; i < n; i++){if(a[i] + k < l){int lf = upper_bound(a, a + n, a[i]) - a, rf = lower_bound(a, a + n, a[i] + k) - a;I += (rf - lf);}else{int lf = upper_bound(a, a + n, a[i]) - a, rf = lower_bound(a, a + n, a[i] + k - l) - a;I += (n - lf);I += rf;}}int inv = ksm(8, mod - 2);int e = (3ll * n + I + V) % mod;e = e * inv % mod;int num = ksm(2, n) % mod;int ans = e * num % mod;cout << ans;
}