poj 3904 Sky Code【容斥原理】

简介: 点击打开链接 Sky Code Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1562   Accepted: 478 Description Stanc...

点击打开链接

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;
}

目录
相关文章
|
SQL 前端开发 JavaScript
基于java+springboot的求职招聘网站-求职招聘管理系统
该系统是基于java+springboot开发的求职招聘网站、网上招聘管理系统、网上人才招聘系统、毕业生求职招聘系统、大学生求职招聘系统、校园招聘系统、企业招聘系统。是给师弟开发的毕业设计。
503 1
|
JavaScript
dialog打开时重新渲染
dialog打开时重新渲染
216 0
|
9月前
|
调度 vr&ar 图形学
【干货】实时云渲染与本地渲染的技术对比
实时渲染分为本地渲染和云渲染两种模式。随着XR技术在建筑、教育、医疗等领域的广泛应用,越来越多企业选择云渲染以提升效率、降低成本并增强协同能力。本文对比分析了这两种渲染模式的优劣,并重点介绍了实时云渲染方案具备便捷性、高效资源调度、超低时延网络、数据安全、终端轻量化及跨系统运行等优势,满足多种XR应用场景需求。
448 13
|
12月前
|
自然语言处理
从原理上总结chatGPT的Prompt的方法
从原理上总结chatGPT的Prompt的方法
158 0
|
Android开发
Android获取横竖屏状态及监听
Android获取横竖屏状态及监听
268 0
|
Oracle 关系型数据库 MySQL
Flink CDC数据同步问题之丢失update操作如何解决
Flink CDC数据同步是指利用Flink CDC实现不同数据源之间的实时数据同步任务;本合集旨在提供Flink CDC数据同步的操作指南、性能优化建议和常见问题处理,助力用户高效实施数据同步。
|
Ubuntu 编译器 网络安全
RK3568开发笔记(七):在宿主机ubuntu上搭建Qt交叉编译开发环境,编译一个Demo,目标板运行Demo测试
在之前的博文中已经搭建好了一个比较完善的ubuntu宿主机,都很完善了但是发现没有Qt交叉编译开发环境,所以还需要搭建一套Qt交叉编译开发环境。
|
Web App开发 编解码 测试技术
什么是兼容性测试?
什么是兼容性测试?
502 0