CSU 1568 Shrine Maintenance

A religious sect has holy sites with shrines placed around a circle of radius 1000. The circle is split into N equal length arcs and the endpoints are numbered in order, 1 through N. The first figure shows a circle where N is 12, with 12 gray tick marks like on a 12-hour analog clock. We can imagine the marks numbered, as on a clock, with 12 at the top. Each circle has one or more sacred numbers associated with it. The sacred numbers for the circle in the first figure are 2 and 3. A shrine, indicated by a black dot in the figure, is placed at each mark whose number is a multiple of at least one of the sacred numbers, so in this case the shrines are at positions 2, 3, 4, 6, 8, 9, 10, and 12.

When it comes time to inspect and repair the shrines at a given site, the area is closed and a team of workers simultaneously fan out from a maintenance shed, located in the center of the circle, so that each shrine is visited by at least one worker. Once all workers have returned to the shed, the site is reopened to the public. Because these sites are in great demand, it is important that they be closed as briefly as possible. In order to minimize this time, they must figure out how to apportion the shrines among the current number of workers, so the maximum distance traveled by any one worker is as small as possible. Figure 1 shows one choice for the optimal solution paths for 3 workers. The lower left path has darker lines, to indicate that it is one with the longest length, which in this case is approximately 3517.6. 
This sect has many circular sites with multiple shrines. The number of available workers at a site, W, the value of the number equal arcs, N, and the sacred numbers vary between sites. The sacred numbers are always divisors of N. Your job is to help figure out how much time is required for maintenance. Figures 2 and 3 show optimal solutions for other sites.

Input

The input consists of one or more data sets. Each data set is on a single line and consists entirely of positive integers. The first three entries are W, the number of workers, N, the number of equal arcs around the circle, and D, the number of sacred divisors of N. At the end come the D divisors of N. W is no more than the total number of shrines; N ≤ 8600, and D ≤ 6; each listed divisor of N is smaller than N.

A single zero, 0, will be placed on the last line to indicate the end of the input.

Output

The output is a single line for each dataset: the maximum distance a worker must travel with an optimal assignment of the shrines. This number is displayed so that it is rounded to one decimal place, and always shows that decimal place, even if it is 0. To ensure unique answers with double arithmetic, the datasets are chosen so that if your answer is anywhere within .005 of the exact minimum distance, then the answer rounded to one decimal place will be the same.

The first three sample datasets correspond to the three figures.

Caution: Be careful with your algorithm so it finishes rapidly.

Sample Input
3 12 2 2 3
7 70 3 14 10 35
2 84 3 3 4 14
4 35 2 7 5
3 20 2 5 4
3 6 1 1
4 6 1 1
1 6 1 1
8600 8600 3 1 10 100
0
Sample Output
3517.6
2624.3
4987.7
3224.9
3488.4
3000.0
3000.0
7000.0
2000.0
一个半径是1000的圆N等分点分别标上号,然后给出一些N的约数,要求标号是这些约数的倍数的点都是可用点,把可用点连上线得到新的图形,然后从圆心出发把新的图分成恰好W份,使得每份的周长最大值最小。
二分答案,去枚举验证,这里有个问题,验证的时候需要按所有点做起点都做一次,但是这样的效率应该会超时,神奇的是可以跑过。。。这里应该需要一个跟gcd有关的东西优化,不过有点不是很好想,就先跳过了。
#include<cstdio>  
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>  
using namespace std;
const double eps = 1e-4;
const int N = 1e5 + 10;
int n, m, d, di;
int f[N], a[N], sz;
double g[N];

bool check(double x) {
	for (int i = 0; i < sz / 2; i++) {
		int cnt = 1;
		double sum = 0;
		for (int j = i + 1; a[j] - a[i] < n; j++) {
			if (sum + g[a[j] - a[j - 1]] <= x) {
				sum += g[a[j] - a[j - 1]];
			} else {
				cnt++; sum = 0;
			}
		}
		if (cnt <= m) return true;
	}
	return false;
}

int main(){
	while (~scanf("%d%d%d", &m, &n, &d) && m) {
		memset(f, 0, sizeof(f));
		sz = 0; 
		for (int i = 0; i < d; i++) {
			scanf("%d", &di);
			for (int j = di; j <= n; j += di) f[j] = 1;
		}
		for (int i = 1; i <= n; i++) {
			if (f[i]) a[sz++] = i, a[sz++] = i + n;
			g[i] = 2000 * sin(acos(-1.0) * i / n);
		}
		sort(a, a + sz);
		double l = 0, r = 2000 * acos(-1.0);
		while (r - l > eps) {
			double mid = (l + r) / 2;
			if (check(mid)) r = mid; else l = mid;
		}
		printf("%.1lf\n", r + 2000);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值