传送门:https://ac.nowcoder.com/acm/contest/9925/I 参考:https://blog.csdn.net/qq_43750980/article/details/111297783
题意
有n个同心圆,圆心都为(0,0),半径依次递增1,2…n 有m条直线将这n个圆等分成2*m份,直线和圆会有交点。 一个交点走向另一个交点只能走有线的路径。
求所有点对距离和。
$$\sum_{i,j\in R\;i\ne j}dis(i,j)$$
题意
这题关键是一个点怎么走向另一个点,这很重要! 首先猜测两个结论:
所以我们可以从小圆推到大圆,接下来就开始操作。
首先预处理半径为1时,一个点到其他所有点的距离和。
维护两个数组,a[i]和b[i] a[i]表示[1,i]个圆内,从1个点出发到该圆内其他所有点的距离和
b[i]表示在第i个圆上,从1个点出发到该圆上其他所有点的距离和
从i=2开始递推,从第i-1个圆推向第i个圆时 b[i]只是从半径为1增大了i倍,所以b[i] = b[1] * i(结论一) a[i]首先要先加b[i]和a[i -1],所以第i和i-1层以内都处理好了。 接着就是第i层的点到所有内层点的距离怎么算? 只需要将第i个圆内层所有点(包括第i个圆上所有点)往里进一层即可(结论二)
- O(n)处理每一层圆得答案
具体看代码
Code(3MS)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| ##include <bits/stdc++.h>
using namespace std;
typedef long long ll; typedef long double ld; typedef pair<int, int> pdd;
##define INF 0x3f3f3f3f ##define lowbit(x) x & (-x) ##define mem(a, b) memset(a , b , sizeof(a)) ##define FOR(i, x, n) for(int i = x;i <= n; i++)
const double PI = acos(-1);
const int N = 1e5 + 10; double a[N], b[N];
void solve() { int n, m; scanf("%d%d",&n,&m);
double cnt = 0; for(int i = 1;i < m; i++) { if(PI * i < 2.0 * m) cnt += PI * i / m; else cnt += 2.0; } cnt *= 2.0; cnt += 2.0; a[1] = b[1] = cnt;
for(int i = 2;i <= n; i++) { b[i] = b[1] * i; a[i] = a[i - 1] + b[i] + 2.0 * m * (i - 1); }
double ans = 0; for(int i = 1;i <= n; i++) { ans += 2.0 * m * (a[i] - b[i]) + 2.0 * m / 2.0 * b[i]; if(m > 1) ans += 2.0 * i * m; } printf("%.10lf\n",ans); }
signed main() { sovle(); }
|
本文作者:jujimeizuo
本文地址: https://blog.jujimeizuo.cn/2020/12/17/2020-icpc-shanghai-i/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!