HDU - 5514 Frogs 容斥(技巧)

題意:給你n種步長,無限走一個圈,圈長m,位置標號從0到m−1,求至少被經過一次的位置之和。 

思路:來自:點擊打開鏈接

大致思路就是用兩個數組記錄每一個因子該算幾遍和已經算了幾遍了。

代碼:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int MAXN = 40010;
int factor[MAXN], step[MAXN], bk[MAXN], num[MAXN];
int main()
{
	int T, n, m;
	cin >> T;
	for(int kase = 1; kase <= T; kase++)
	{
		int cnt = 0;
		memset(bk, 0, sizeof(bk));
		memset(num, 0, sizeof(num));
		scanf("%d %d", &n, &m);
		for(int i = 1; i * i <= m; i++)
		if(m % i == 0)
		{
			factor[cnt++] = i;
			if(m / i != i) 
			factor[cnt++] = m / i;		
		}
		sort(factor, factor + cnt);
		cnt--;//把m去除 
		for(int i = 1; i <= n; i++)
		{
			scanf("%d", step + i);
			step[i] = __gcd(step[i], m);
			for(int j = 0; j < cnt; j++)
			{
				if(factor[j] % step[i] == 0)
				bk[j] = 1;
			}
		}
		ll ans = 0, tmp;
		for(int i = 0; i < cnt; i++)
		{
			if(bk[i] == num[i]) continue;
			tmp = (m - 1) / factor[i];//注意是用 m - 1 除
			ans += 1ll * tmp * (tmp + 1) / 2 * factor[i] * (bk[i] - num[i]);
			tmp = bk[i] - num[i];
			for(int j = i; j < cnt; j++)
			{
				if(factor[j] % factor[i] == 0)
				num[j] += tmp;
			}
		}
		printf("Case #%d: %lld\n", kase, ans);
	}
 	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章