生活随笔
收集整理的這篇文章主要介紹了
hdu 5514 容斥
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
hdu 5514
題意:有n個青蛙編號1~n,m塊石頭編號0~m-1,石頭圍成一圈,每只青蛙會從第i塊跳到第(i + ai) mod m塊,青蛙會跳無數(shù)次,問被青蛙踩過的石頭編號的和是多少。
思路:對所有ai求gcd(ai, m)得bi,對于每個bi,編號為bi的倍數(shù)的石頭一定也被踩過,但是會被重復(fù)踩。
求m的所有因子f,這些bi必定在f中,f中的數(shù)有青蛙踩過一次的,也有踩過多次的,我們只希望它們被踩一次。
所以設(shè)定f中的數(shù)要恰好被踩一次,將f中的數(shù)排序然后依次覆蓋它的倍數(shù),f中不是素因子的數(shù)就會被它的因子重復(fù)覆蓋,實(shí)際上這就是一個容斥的過程。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
typedef long long LL;
const int INF =
1 <<
30;
const long long LINF =
1LL <<
50;
const int MAXM =
1e5 +
5;
const int MAXN =
1e5 +
5;
const double PI =
acos(-
1.0);
const double eps =
1e-6;
int n, m;
int gcd(
int a,
int b){
return a % b ==
0 ? b : gcd(b, a % b);
}
int cnt[MAXM], factors[MAXM];
bool vis[MAXM];
int main(){
#ifndef ONLINE_JUDGE#endifint t;
scanf(
"%d", &t);
for(
int cas =
1; cas <= t; cas++){
scanf(
"%d %d", &n, &m);LL tmp =
sqrt(m), k =
0;
for(
int i =
1; i <= tmp; i++) {
if(m % i ==
0){factors[k++] = i;
if(i * i != m) factors[k++] = m / i;}}sort(factors, factors + k);k--;
memset(cnt,
0,
sizeof cnt);
memset(vis,
0,
sizeof vis);
for(
int i =
0; i < n; i++){LL a;
scanf(
"%I64d", &a);tmp = gcd(a, m);
for(
int j =
0; j < k; j++)
if(factors[j] % tmp ==
0)vis[j] =
true;}LL ans =
0;
for(
int i =
0; i < k; i++){
if(vis[i] != cnt[i]){tmp = m / factors[i];ans += tmp * (tmp -
1) /
2 * factors[i] * (vis[i] - cnt[i]);tmp = vis[i] - cnt[i];
for(
int j = i; j < k; j++){
if(factors[j] % factors[i] ==
0)cnt[j] += tmp;}}}
printf(
"Case #%d: %I64d\n", cas, ans);}
return 0;
}
總結(jié)
以上是生活随笔為你收集整理的hdu 5514 容斥的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。