Answer:21025060
这题感觉非常的OI。
一开始以为是斜率优化一类的东西,后来发现想复杂了。
这题的亮点是数据随机。
考虑点x。我们找当前点y(注意在递归是y可以不等于x)前面那个点z,如果z能看得见,那么y<-z并递归。否则我们猜测:x能看到的下一个点一定属于y能看到的点。
这个结论比较显然,如果x能看到的下一个点s,y看不到,那么在s之前一定有一个点w挡住了y,由于y要求的斜率比x要大,如果挡住了y(即
slope w−y>slope s−y
),那么一定挡住x(即
slope w−x>slope s−x
)。所以原猜想成立。
然后根据
S(100)100=2.27
可以推测
S(2500000)2500000
不会很大。于是我们暴力寻找下一个x能看到的点即可。复杂度应该是
O(ans∗max{couldsee})
,其中
couldseei
为点i的可见点数量。
跑了
11s
。然而
O(n2)
的居然也就50min。。。
听说还有人猜测所有的可见点距离不会超过
40000
,暴力居然只跑了
2min
,这让我这种非暴力党情何以堪TAT
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int n = 2500000;
int Pr[2 * n + 10], t = 0, ans = 0;
ll H1[2 * n + 10], H2[2 * n + 10];
bool B[90000010];
vector <int> S[n + 10];
bool check(int a, int b, int c)
{
return (H2[c] - H2[a]) * (H1[c] - H1[b]) <= (H2[c] - H2[b]) * (H1[c] - H1[a]);
}
int main()
{
for(int i = 2; i <= 90000000; i++) {
if(!B[i]) {Pr[++t] = i; if(t == 5000000) break;}
for(int j = 1; Pr[j] * i <= 90000000; j++) {
B[Pr[j] * i] = 1;
if(i % Pr[j] == 0) break;
}
}
H1[1] = 2;
for(int i = 2; i <= 2500000; i++) {
H1[i] = H1[i - 1] + Pr[i * 2 - 1] + Pr[i * 2 - 2];
H2[i] = H2[i - 1] + Pr[i * 2 - 1] - Pr[i * 2 - 2];
}
for(int i = 2; i <= n; i++) {
for(int s = i - 1; ;) {
S[i].push_back(s), ans++;
bool flag = 0;
for(int j = 0; j < S[s].size(); j++)
if(check(S[s][j], s, i)) {
s = S[s][j], flag = 1;
break;
}
if(!flag) break;
}
return printf("%d\n", ans), 0;
}