D. Moving Dots
We play a game with $n$ dots on a number line.
The initial coordinate of the $i$-th dot is $x_i$. These coordinates are distinct. Every dot starts moving simultaneously with the same constant speed.
Each dot moves in the direction of the closest dot (different from itself) until it meets another dot. In the case of a tie, it goes to the left. Two dots meet if they are in the same coordinate, after that, they stop moving.
After enough time, every dot stops moving. The result of a game is the number of distinct coordinates where the dots stop.
Because this game is too easy, calculate the sum of results when we play the game for every subset of the given $n$ dots that has at least two dots. As the result can be very large, print the sum modulo $10^9+7$.
Input
The first line contains one integer $n$ ($2 \leq n \leq 3000$).
The next line contains $n$ integers $x_1, x_2, \ldots, x_n$ ($1 \leq x_1 < x_2 < \ldots < x_n \leq 10^9$), where $x_i$ represents the initial coordinate of $i$-th dot.
Output
Print the sum of results modulo $10^9+7$.
Examples
input
4 1 2 4 6
output
11
input
5 1 3 5 11 15
output
30
Note
In the first example, for a subset of size $2$, two dots move toward each other, so there is $1$ coordinate where the dots stop.
For a subset of size $3$, the first dot and third dot move toward the second dot, so there is $1$ coordinate where the dots stop no matter the direction where the second dot moves.
For $[1, 2, 4, 6]$, the first and second dots move toward each other. For the third dot, initially, the second dot and the fourth dot are the closest dots. Since it is a tie, the third dot moves left. The fourth dot also moves left. So there is $1$ coordinate where the dots stop, which is $1.5$.
Because there are $6$ subsets of size $2$, $4$ subsets of size $3$ and one subset of size $4$, the answer is $6 \cdot 1 + 4 \cdot 1 + 1 = 11$.
In the second example, for a subset of size $5$ (when there are dots at $1$, $3$, $5$, $11$, $15$), dots at $1$ and $11$ will move right and dots at $3$, $5$, $15$ will move left. Dots at $1$, $3$, $5$ will eventually meet at $2$, and dots at $11$ and $15$ will meet at $13$, so there are $2$ coordinates where the dots stop.
解题思路
题目看了半天都没看懂。大概就是每次从点集里面选择一个子集(至少要有两个元素),然后每个点都以相同的速度向距离它最近的点移动(如果距离两边的点都相同则统一向左移动),如果碰到其他点则停止移动,最后数轴上不动的点有为$x$个。问在所有的子集中,$x$的总和是多少。
这题最关键的地方是要想到数轴最终留下的点必然是由子集序列中相邻的两个点相遇所形成的。因此可以枚举点对$(x_i, x_j)$,统计每个点对能够贡献的答案是多少。如果想让$x_i$和$x_j$相遇成为最后留下的点,那么首先在$x_i < x_k < x_j$范围内的点不能选。同时,我们还要保证$x_i$向左移动$x_j$向右移动,记$d = x_j - x_i$,那么$x_i - d \leq x_k < x_i$和$x_j < x_k \leq x_j + d - 1$内的点不能选。假设通过二分出来$x_i$左边有$l$个点可以选,$x_j$右边有$r$个点可以选,那么最终留下由$(x_i, x_j)$形成的点的集合个数就是$2^{l+r}$。
AC代码如下,时间复杂度为$O(n^2 \log {n})$:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 3010, mod = 1e9 + 7; 7 8 int n; 9 int a[N]; 10 11 int qmi(int a, int k) { 12 int ret = 1; 13 while (k) { 14 if (k & 1) ret = 1ll * ret * a % mod; 15 a = 1ll * a * a % mod; 16 k >>= 1; 17 } 18 return ret; 19 } 20 21 int find(int x) { // 二分找到大于等于x的最小下标 22 int l = 1, r = n + 1; 23 while (l < r) { 24 int mid = l + r >> 1; 25 if (a[mid] >= x) r = mid; 26 else l = mid + 1; 27 } 28 return l; 29 } 30 31 int main() { 32 scanf("%d", &n); 33 for (int i = 1; i <= n; i++) { 34 scanf("%d", a + i); 35 } 36 a[n + 1] = 2e9; // 加个哨兵,保证可以二分出结果 37 int ret = 0; 38 for (int i = 1; i <= n; i++) { 39 for (int j = i + 1; j <= n; j++) { 40 int d = a[j] - a[i]; 41 int l = find(a[i] - d) - 1; // 左边可以选的点数 42 int r = n - find(a[j] + d) + 1; // 右边可以选的点数 43 ret = (ret + qmi(2, l + r)) % mod; // 快速幂求2^{l+r} 44 } 45 } 46 printf("%d", ret); 47 48 return 0; 49 }
参考资料
Codeforces Round #851 (Div. 2) Editorial:https://codeforces.com/blog/entry/112584
标签:Dots,dots,int,stop,Moving,11,where,dot From: https://www.cnblogs.com/onlyblues/p/17112585.html