poj 3904 Sky Code

点击打开链接

Sky Code

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 1562   Accepted: 478

Description

Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to steal the spacecraft of Petru. There is only one problem – Petru has locked the spacecraft with a sophisticated cryptosystem
based on the ID numbers of the stars from the Milky Way Galaxy. For breaking the system Stancu has to check each subset of four stars such that the only common divisor of their numbers is 1. Nasty, isn’t it? Fortunately, Stancu has succeeded to limit the number
of the interesting stars to N but, any way, the possible subsets of four stars can be too many. Help him to find their number and to decide if there is a chance to break the system.

Input

In the input file several test cases are given. For each test case on the first line the number N of interesting stars is given (1 ≤ N ≤ 10000). The second line of the test case contains the list of ID numbers of the interesting stars, separated by spaces.
Each ID is a positive integer which is no greater than 10000. The input data terminate with the end of file.

Output

For each test case the program should print one line with the number of subsets with the asked property.

Sample Input

4
2 3 4 5
4
2 4 6 8
7
2 3 4 5 7 6 8

Sample Output

1
0
34

题目翻译:给出n(n<10000)个数,这些数<=10000,要求选出四个数字且他们的最大公约数为1的(注意:不需要两两互质),有多少种选法。

解题思路:本题可以先计算n个数字选四个总共有多少种选法,然后减去公约数不是1的。把共同具有某一素因子的数字划分到同一个集合,属于统一集合的四个数最大公约数一定大于1,如果四个数字不同时属于任何集合则最大公约数一定为1。用总的组合数减去那些四个数字同时被同一个集合包括了的组合数,所得结果即为最终答案。但是这些一个四个数字的组合可能同时属于若干个集合,因此需要在这些集合之间进行容斥原理,以求每个需要被减去的四个数字的组合都恰好被减掉一次。

首先,先将算法流程说一下,原理后面会有

Step 1:预处理,求组合数C(n,4),存于数组p中,方便下面运算!

Step 2:组合素数,用prime数组记录由m(m<=5)个素数相乘所得数的素因子

Step 3:读入当前数为a,将a分解为质因数形式,注意每个质因数只被记录一次

例如:  182=2*7*13 ———> m=3 so,相加

2=2 ——>m=1 so,相加

91=7*13 ——>m=2 so,相减

注意12=2^2*3等这种是B=p1^k1*p2^k2+...这种有质因数指数不为一的合数记录不同因子的个数

12=2*2*3 则 12会被分为2*3,多余的2被消去了,因此m=2;

Step 4:将分出的素数进行组合,并统计每种的方案数

例如:12=2^2*3——>12=2*3——>cnt[2]++,cnt[3]++,cnt[6]++

Step 5:处理之后,ans赋值为0

Step 6:for i 2-->10000

if (m==奇数)    ans:=ans+C(cnt[i],4)

else    ans:=and-C(cnt[i],4);

Step 7:输出ans

原理:首先考虑一个问题,1000以内6,7,8,9的倍数有多少个?答案是

1000div6+1000div7+1000div8+1000div9

-1000div(6*7)-1000div(6*8)-1000div(6*9)-1000div(7*8)-1000div(7*9)-1000div(8*9)

+1000div(6*7*8)+1000div(6*8*9)+1000div(7*8*9)

-1000div(6*7*8*9)

这是容斥原理的一个最简单的应用,类比这道题,Step3到4其实将每个数a的不重复约数记录了下来,

有公共约数的四个数的方案要从ans中减去,多减的要加上

显然m为奇时要减,m为偶时要加,这和”1000以内6,7,8,9的倍数有多少个?“这个问题奇偶是反的,

由于a最大为10000,所以m最大可以有5 (2*3*5*7*11<10000,2*3*5*7*11*13>10000)

此表格解释利用2进制查找素因子组合

  1 2 4
1 T    
2   T  
3 T T  
4     T
5 T   T
6   T T
7 T T T
#include<iostream>
#include<stdio.h>
#include<string.h>
#define MAX 10005
using namespace std;
int cnt[MAX],num[MAX],prime[5];//数组不必过大,5个单位即可
long long  p[MAX]={0}; //必须用大整数
void Solve(int  n){
    int i,j,tol=0,k,sum;
    for(i=2;i*i<=n;i++){ //计算素因子个数
        if(n%i==0)
            prime[tol++]=i;
        while(n%i==0)//去重复因子
            n/=i;
    }
    if(n!=1) prime[tol++]=n;    //如果本身就是大于n开方的素数,需要加一,这点不要忘记
    for(i=1;i<(1<<tol);i++){  //总共有1~2^tol-1个组合
        k=1,sum=0;
        for(j=0;j<tol;j++)//巧妙利用二进制来查找到所有素因子组合构成的数
            if(i&(1<<j)){
                k*=prime[j];
                sum++;
            }
        cnt[k]++; //记录含有因子K的数的个数,比如n=30,则cnt[2]++,cnt[3]++,cnt[5]++;
                                            //cnt[6]++,cnt[10]++,cnt[15]++;cnt[30]++;
        num[k]=sum;//记录k中含有素因子的个数 num[2]=1,num[3]=1,num[5]=1,num[6]=2,
    }                                       //num[10]=2,num[15]=2,num[30]=3,
}
int main(){
   int m,n;
   long long i;
   for(i=4;i<MAX;i++)        //先打表,提高效率,i<4时p[i]为0;
        p[i]=i*(i-1)*(i-2)*(i-3)/24;
   while(~scanf("%d",&n)){
       memset(cnt,0,sizeof(cnt));
       for(i=0;i<n;i++){
           scanf("%d",&m);
           Solve(m);        //求解其素因子,并统计相关数据
       }
       long long ans=0;
       for(i=0;i<MAX;i++)
           if(cnt[i]>=4)//剪枝,必须大于等于四
               if(num[i]&1) //假如含有素因子个数为奇数,则加上;否则减去
                    ans+=p[cnt[i]];
               else
                    ans-=p[cnt[i]];
       cout<<p[n]-ans<<endl; //最后用总的减去不符合的四元组个数
   }return 0;
}
时间: 2024-08-10 02:03:25

poj 3904 Sky Code的相关文章

POJ 3904 Sky Code (容斥+莫比乌斯反演)

Sky Code Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1831   Accepted: 570 Description Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to ste

POJ 3904 Sky Code (容斥原理)

题意:给定n个数,从n个数找出四个数,使这四个数的最大公约数为1,找出有多少对这样的组合. 找最大公约数不是1的有多少对. 题解:四个数的公约数为1,并不代表四个数两两互质.比如(2,3,4,5)公约数为1,但是 2和4并不互质.从反面考虑,先求出四个数公约数不为1的情况个数,用总的方案个数 减去四个数公约数不为1的情况个数就是所求. 求四个数公约数不为1的情况个数,需要将N个数每个数质因数分解,纪录下所有不同 的素因子所能组成的因子(就是4个数的公约数),并统计构成每种因子的素因子个数, 和因

[容斥原理] poj 3094 Sky Code

题目链接: http://poj.org/problem?id=3904 Sky Code Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1334   Accepted: 405 Description Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraf

POJ Sky Code 莫比乌斯反演

N. Sky Code Time Limit: 1000ms Case Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Submit Status Font Size: + - Stancu likes space travels but he is a poor software developer and will never be able

Sky Code(poj3904)

Sky Code Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2085   Accepted: 665 Description Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to ste

POJ 3904(容斥原理)

Sky Code Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1750   Accepted: 545 Description Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to ste

poj3904 Sky Code

Sky Code Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1694   Accepted: 523 Description Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to ste

【POJ 1850】 Code

[POJ 1850] Code 还是非常想说 数位dp真的非常方便! !. 数位dp真的非常方便!.! 数位dp真的非常方便! !! 重要的事说三遍 该题转换规则跟进制差点儿相同 到z时进一位 如az下位为bc 上位必须比下位小 依据这个规则搜出全部情况就可以 #include <iostream> #include <cstdio> #include <cstring> using namespace std; int dp[11][27]; int digit[11

POJ3094 Sky Code(莫比乌斯反演)

POJ3094 Sky Code(莫比乌斯反演) Sky Code 题意 给你\(n\le 10^5\)个数,这些数\(\le 10^5\),问这些这些数组成的互不相同的无序四元组(a,b,c,d)使得gcd(a,b,c,d)=1的四元组有多少? 解法 枚举一个约数\(k\),看看总共有多少个数\(S_k=\{x\}\)满足\(k|x\).那么可以保证(a,b,c,d)有的一个共同的因子是k,这样的四元组的个数就是 \[ F(k)={|S_k|\choose 4} \] 这样算会算重,比如枚举到