【发布时间】:2013-01-13 03:51:28
【问题描述】:
我正在尝试解决在线法官问题:http://opc.iarcs.org.in/index.php/problems/LEAFEAT
简而言之问题:
如果给定一个整数 L 和一组 N 个整数 s1,s2,s3..sN,我们必须找出从 0 到 L-1 有多少个数不能被任何 'si' 整除.
例如,如果给定L = 20 和S = {3,2,5},则从 0 到 19 有 6 个数字不能被 3,2 或 5 整除。
L
我使用了Inclusion-Exclusion原理来解决这个问题:
/*Let 'T' be the number of integers that are divisible by any of the 'si's in the
given range*/
for i in range 1 to N
for all subsets A of length i
if i is odd then:
T += 1 + (L-1)/lcm(all the elements of A)
else
T -= 1 + (L-1)/lcm(all the elements of A)
return T
这是我解决这个问题的代码
#include <stdio.h>
int N;
long long int L;
int C[30];
typedef struct{int i, key;}subset_e;
subset_e A[30];
int k;
int gcd(a,b){
int t;
while(b != 0){
t = a%b;
a = b;
b = t;
}
return a;
}
long long int lcm(int a, int b){
return (a*b)/gcd(a,b);
}
long long int getlcm(int n){
if(n == 1){
return A[0].key;
}
int i;
long long int rlcm = lcm(A[0].key,A[1].key);
for(i = 2;i < n; i++){
rlcm = lcm(rlcm,A[i].key);
}
return rlcm;
}
int next_subset(int n){
if(k == n-1 && A[k].i == N-1){
if(k == 0){
return 0;
}
k--;
}
while(k < n-1 && A[k].i == A[k+1].i-1){
if(k <= 0){
return 0;
}
k--;
}
A[k].key = C[A[k].i+1];
A[k].i++;
return 1;
}
int main(){
int i,j,add;
long long int sum = 0,g,temp;
scanf("%lld%d",&L,&N);
for(i = 0;i < N; i++){
scanf("%d",&C[i]);
}
for(i = 1; i <= N; i++){
add = i%2;
for(j = 0;j < i; j++){
A[j].key = C[j];
A[j].i = j;
}
temp = getlcm(i);
g = 1 + (L-1)/temp;
if(add){
sum += g;
} else {
sum -= g;
}
k = i-1;
while(next_subset(i)){
temp = getlcm(i);
g = 1 + (L-1)/temp;
if(add){
sum += g;
} else {
sum -= g;
}
}
}
printf("%lld",L-sum);
return 0;
}
next_subset(n) 生成数组A 中大小为 n 的下一个子集,如果没有子集,则返回 0,否则返回 1。它基于this stackoverflow 中接受的答案所描述的算法问题。
lcm(a,b) 函数返回 a 和 b 的 lcm。
get_lcm(n) 函数返回A 中所有元素的lcm。
它使用属性:LCM(a,b,c) = LCM(LCM(a,b),c)
当我将问题提交给法官时,它会给我一个“超出时间限制”。如果我们用蛮力解决这个问题,我们只能得到 50% 的分数。
由于最多可以有 2^20 个子集,我的算法可能会很慢,因此我需要一个更好的算法来解决这个问题。
编辑:
在编辑我的代码并将函数更改为欧几里得算法后,我得到了错误的答案,但我的代码在时间限制内运行。它给了我对示例测试的正确答案,但对任何其他测试用例都没有;这是我运行代码的ideone 的链接,第一个输出是正确的,但第二个不是。
我解决这个问题的方法正确吗?如果是,那么我在代码中犯了一个错误,我会找到它;否则任何人都可以解释什么是错的吗?
【问题讨论】:
-
+1 为这个网站提供了这么多有趣的问题。去工作!
-
lcm 和 gcd 函数应该占用 a、b 一样长的时间。