您的位置:首页 > 其它

poj3904 Sky Code【容斥原理】

2016-03-25 21:43 471 查看
Sky Code

Time Limit: 1000MSMemory Limit: 65536K
Total Submissions: 1977Accepted: 635
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

Source

Southeastern European Regional Programming Contest 2008
[Submit] [Go Back] [Status]
[Discuss]


Home Page

Go
Back

To top

题意:
就是输入一个数N,代表密码的可能数字,然后再输入N个数,然后看看这N个数中有多少个组合(四个数组成,并且这四个数只有一个公约数为1,也就是互质!).
思路:
裸的容斥原理!
第一道容斥原理题,所以就在这里说一下我的理解!
首先先输入N个数,在输入这N个数的同时先求出这些数的质因数,并且统计这些质因数的个数tot,然后再通过循环找将这些质因数进行组合(总共2^tot-1个),然后利用二进制数的特点(1所在的位置代表这个位置上的素数),将所有的组合(也就是该数的因数)枚举一遍,在枚举的同时将这个数是由几个素数相乘得到的也顺便求出来,然后再遍历所有的数,并且判断这些数的cnt是否大于等于4(也就是有这样的因数的数的个数是否大于等于4),如果大于等于4,则说明这个数至少是输入的数中的4个数的质因数,然后再看看这个数是由几个质数组成的,如果是奇数个,那么就把p[cnt[i]]加到ans上,如果是偶数个就把p[cnt[i]]减去(因为这种组合会重复,所以需要用到加奇减偶思想!),得到的ans就是我们要求的至少有4个相同质因数的数的组合的个数,然后用p
-ans即为所求!(ans统计的是有质因数的数,然后p
统计的是n中挑4个的所有可能的数,然后p
-ans就是只有一个质因数的数的个数!)
加奇减偶思想实例:1,2,3,4,5,6这六个数中能被1,2,整除的数的个数!6/1+6/2-6/(1*2);也就是找到能被1整除的数的个数加上能被2整除的数的个数,然后减去能够被1和2同时整除的数的个数,就是要求的数的个数!这个是最简单的实例,将其扩展之后就是加奇减偶的思想!
代码:
//容斥原理!!!
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int m,cnt[10000+5],num[10000+5];
long long p[10000+5]={0};
int prim[10];
void solve(int n)
{
int tot=0;//质因数的个数(也就是素数的个数)
for(int i=2;i*i<=n;i++)
{
if(n%i==0)//i就是质因数
prim[tot++]=i;//prim数组保存的是第tot个质因数
while(n%i==0)//如果有多个相同的质因数的话就将它都除掉
n/=i;
}
if(n!=1) prim[tot++]=n;//如果存在n为素数就将它直接赋值给prim就OK了!
//例如:n=7的时候就是这种情况
for(int i=1;i<(1<<tot);i++)//总共的素数的组合数为1-2^tot-1
{//正好对应该数的二进制中1的位置上的素数的组合(1的组合就是素数的组合)
int k=1,sum=0;
for(int j=0;j<tot;j++)//遍历多有的位置上是否有1
{
if(i&(1<<j))//如果第j+1个位置上有1
{
k*=prim[j];//那么就将prim[j]乘到k上(也就是将二进制中位置上是1的那个位置上的prim值乘到k上)
sum++;//sum用来统计k是由几个素数组成的
}
}
cnt[k]++;//算出k之后将k的个数加1
num[k]=sum;//并且将k是由几个质因数组成的赋值给num数组
}
}
int main()
{
for(int i=4;i<10000+1;i++)//先初始化,找i中挑选4个的可能数 (小于4的话肯定为0)
{
p[i]=(long long)i*(i-1)*(i-2)*(i-3)/24;
}
int n;
while(scanf("%d",&n)!=EOF)
{
memset(cnt,0,sizeof(cnt));
memset(num,0,sizeof(num));
for(int i=0;i<n;i++)
{
scanf("%d",&m);
solve(m);//将输入的数进行质因数分解,并且统计这些质因数的所有的组合的个数
}//这些质因数的组合也是m的因数
long long ans=0;//统计所有的由4个数组成的一组数(它有相同的质因数 )的个数!
for(int i=0;i<10000+1;i++)
{
if(cnt[i]>=4)
{
if(num[i]&1)//因数i由num[i]个质因数组成,如果num[i]为奇数时
ans+=p[cnt[i]];//从有相同质因数i的cnt[i]个数中挑选4个的可能个数加到ans上
else//为偶数时
ans-=p[cnt[i]];//就减去所有的可能个数
}//这个统计的是四个数有相同质因数的数的组数
}
printf("%lld\n",p
-ans);//用总的组数减去有相同质因数的数的组数就是只有一个质因数1的数的组数
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: