hihocoder 1246 王胖浩与环

题意:

给出一个环,环上有n(<=2000)个数字(<=5e7),然后将这个环分成1~n个连续序列,各个序列和之间的最大公因数。

 

题解:

我一开始想到的是二分,然后对于二分就会想怎么check,那么可以枚举这n个数和的因数,因为答案一定在这里面,然后就会找出对于每个因数可以分成的段数,但是这个并不满足单调性QAQ,但提供了一定的思路

考虑从大到小枚举因数,然后对于这个因数分成尽量多的部分,因为不难知道如果a % x == 0,(a + b) % x == 0 那么b % x == 0,因为这样就可以一直贪心找最大的因数。

然后现在的问题就是考虑环的情况,一般的做法是断环为链,枚举起点到终点找出有多少段%x == 0,但是可以稍微变一下形,如果pre[i] % x == y, pre[j] % x == y,那么i ~ j这一段%x为0,那么(1 ~ i) + (j+1 ~ n) % x == 0,那么现在的问题就是统计余数出现最多的次数,就完美处理了环的情况。

 

代码:

 

#include <bits/stdc++.h>
using namespace std;

const int N = 4e3 + 7;
#define LL long long
vector <LL> num;
int n;
LL pre[N];

int main () {
	scanf ("%d", &n);
	for (int i = 1; i <= n; ++i) {
		int x;
		scanf ("%d", &x);
		pre[i] = pre[i-1] + x;
	}
	for (LL i = 1; i * i <= pre[n]; ++i) {
		if (pre[n] % i == 0) {
			if (i * i == pre[n]) {
				num.push_back(i);
				continue;
			}
			num.push_back(i);
			num.push_back(pre[n] / i);
		}
	}
	sort (num.begin(), num.end());
	int K = 1;
	for (int i = num.size() - 1; i >= 0; --i) {
		int maxi = 0;
		vector <LL> v;
		for (int j = 1; j <= n; ++j) v.push_back(pre[j] % num[i]);
		sort (v.begin(), v.end());
		int pre = 0;
		for (int j = 0; j < v.size(); ++j) {
			if (v[j] == v[j+1] && j != v.size()-1) continue;
			maxi = max (maxi, j - pre + 1);
			pre = j + 1;
		}
		while (K <= maxi) {
			printf ("%lld\n", num[i]);
			++K;
		}
	}
	return 0;
}

  

总结:

这种求因数的题,并且数的范围不大,可以直接暴力枚举因数。。。。。。还有注意的是公式的变换~

posted @ 2016-10-31 20:42  xgtao  阅读(205)  评论(0编辑  收藏  举报