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-10-24 09:53:30

poj 3904 Sky Code【容斥原理】的相关文章

poj 2773 Happy2006【容斥原理】

Happy 2006 Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 9936   Accepted: 3411 Description Two positive integers are said to be relatively prime to each other if the Great Common Divisor (GCD) is 1. For instance, 1, 3, 5, 7, 9...are al

POJ 1780 Code:十进制格雷码&amp;amp;欧拉回路

Description KEY Inc., the leading company in security hardware, has developed a new kind of safe. To unlock it, you don't need a key but you are required to enter the correct n-digit code on a keypad (as if this were something new!). There are severa

poj 1850 Code

点击打开链接poj 1850 思路:组合数学+排列组合 分析: 1 题目要求的是给定一个字符串判断是否满足题目的要求,如果是输出第几个,如果不是则输出-1. 2 那么首先我们应该先判断这个字符串是否是符合题目的字符串,如果不符和直接输出-1. 3 在字符串符合的情况下,那么我们就可以知道长度小于len的字符串都是符合条件的.    现在长度为n的字符串最多可以到达的编号就是num = C(26,1)+C(26,2)+......+C(26,n);    那么我们只要把不合法的全部扣除即可找到这个

POJ题目分类

初期: 一.基本算法:      (1)枚举. (poj1753,poj2965)      (2)贪心(poj1328,poj2109,poj2586)      (3)递归和分治法.      (4)递推.      (5)构造法.(poj3295)      (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996) 二.图算法:      (1)图的深度优先遍历和广度优先遍历.      (2)最短路径算法(dijkstra,bellman-ford

poj分类

初期: 一.基本算法:      (1)枚举. (poj1753,poj2965)      (2)贪心(poj1328,poj2109,poj2586)      (3)递归和分治法.      (4)递推.      (5)构造法.(poj3295)      (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996) 二.图算法:      (1)图的深度优先遍历和广度优先遍历.      (2)最短路径算法(dijkstra,bellman-ford

UVa 706 / POJ 1102 LCD Display (模拟)

706 - LCD Display Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=647 http://poj.org/problem?id=1102 A friend of you has just bought a new computer. Until

poj 1125 Floyd算法

一.题目大意 可以说理解题目比解题难~~明显的多源最短路径,我用的Floyd,Floyd也可以算是dp的一种. 题目可能有多组测试数据,每个测试数据的第一行为经纪人数量N(当N=0时,输入数据结束),然后接下来N行描述第i(1<=i<=N)个经纪人与其他经纪人的关系.每行开头数字M为该行对应的经纪人有多少个经纪人朋友(该节点的出度,可以为0),然后紧接着M对整数,每对整数表示成a,b,则表明该经纪人向第a个经纪人传递信息需要b单位时间(即第i号结点到第a号结点的孤长为b),整张图为有向图,即弧

打印机语言-ZPL指令设置QR code二维码无法转向的问题。

问题描述 ZPL指令设置QR code二维码无法转向的问题. 用ZPL指令生成QR CODE时,无法支持转向,该如何实现.如下^BQN,QR CODE只支持N一个参数. ^XA ^FO100,100 ^BQN,2,10 ^FD1234567890123456^FS ^XZ

Print2Flash出现&amp;quot;System Error. Code:1722. RPC服务器不可用.&amp;quot;错误解决办法

Print2Flash出现"System Error. Code:1722. RPC服务器不可用."错误. 一般来说这个应该是某个Windows服务没有打开所导致的问题.后来才发现:原来是Print Spooler这个服务没有启动,只要启动这个服务就可以了,启动的时候就不会报错了.