链接:http://acm.hdu.edu.cn/showproblem.php?pid=1796
Time Limit: 12000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5612 Accepted Submission(s): 1608
For each case, output the number.
12 2 2 3
7
#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <iomanip>
#include <ctime>
#include <climits>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <map>
//#pragma comment(linker, "/STACK:102400000, 102400000")
using namespace std;
typedef unsigned int li;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double pi = acos(-1.0);
const double e = exp(1.0);
const double eps = 1e-8;
const int maxm = 15; // 集合最大计数
int num[maxm]; // m个数的集合
int n, m, cnt; // 给定数n,集合计数m,不为零的m集合计数
int ans; // 最后所求结果
int gcd(int a, int b); // 求最大公约数
int lcm(int a, int b); // 求最小公倍数
void dfs(int index, int common, int sign); // 利用深搜展现容斥原理
int main()
{
ios::sync_with_stdio(false);
while (~scanf("%d%d", &n, &m))
{
int x; // 集合元素
cnt = 0;
while (m--)
{
scanf("%d", &x);
if (0 == x) // 集合元素可能含有零,丢弃零
continue;
num[cnt++] = x; // 不为零的元素存入集合
}
ans = 0; // 初始化最后所求结果
for (int i=0; i<cnt; i++)
dfs(i, num[i], 1); // 枚举m集合中非零元素进行深搜
printf("%d\n", ans);
}
return 0;
}
int gcd(int a, int b)
{ // 欧几里得算法/辗转相除法
return b ? gcd(b, a%b) : a;
}
int lcm(int a, int b)
{ // 这样写,有利于防止中间过程溢出
return a/gcd(a, b)*b;
}
void dfs(int index, int common, int sign)
{ // 集合元素的索引,最小公倍数,符号判断(容斥公式中的奇数项加偶数项减)
common = lcm(num[index], common);
if (sign & 1) // 奇数项加
ans += (n-1)/common; // 小于n的数,所以用n-1
else // 偶数项减
ans -= (n-1)/common;
for (int i=index+1; i<cnt; ++i)
dfs(i, common, sign+1); // 一层是找出一个元素的子集最小公倍数的计数
// 两层是找出两个元素的子集最小公倍数的计数
// 以此类推,所有子集最小公倍数的计数都找出
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 1796 How many integers can you find
原文地址:http://blog.csdn.net/silenceneo/article/details/47831943