现在的位置: 首页 > 综合 > 正文

poj 3904 sky code 容斥原理

2012年08月14日 ⁄ 综合 ⁄ 共 1919字 ⁄ 字号 评论关闭

给定n个数,求互质的四元组的个数。

逆向思考,先求不互质的四元组的个数,再减掉。

举个例子:以2为因子的数有a个,3为因子 的数有b个,6为因子的数有c个,假设有n个数

那么互质的四元组个数为C(4,a)+C(4,b)-C(4,c),即如果一个数仅由偶数个素数相乘所得,则减去,由奇数个素数相乘,则加上

通用做法

View Code

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const __int64 maxn=10005;
__int64 count[maxn];
__int64 P[maxn],num[maxn];
__int64 Prime[maxn];
void init(){
__int64 i;
memset(P,0,sizeof(P));
memset(num,0,sizeof(num));
for(i=4;i<maxn;i++){
P[i]=i*(i-1)*(i-2)*(i-3)/24;
}
}
void gao(__int64 x){
__int64 i,j;
__int64 n=x,tot=0;
for(i=2;i*i<=n;i++){
if(n%i==0) Prime[tot++]=i;
while(n%i==0)n/=i;
}
if(n>1)Prime[tot++]=n;
for(i=1;i<(1<<tot);i++){
__int64 ji=1;
__int64 sum=0;
for(j=0;j<tot;j++)if(i&(1<<j)){
ji*=Prime[j];
sum++;
}
count[ji]++;
num[ji]=sum;
}
}
int main(){
__int64 i,in,n;
init();
while(scanf("%I64d",&n)!=-1){
memset(count,0,sizeof(count));
for(i=0;i<n;i++){
scanf("%I64d",&in);
gao(in);
}
__int64 ans=0;
for(i=0;i<maxn;i++)if(count[i]){
if(num[i]%2) ans+=P[count[i]];
else ans-=P[count[i]];
}
ans=P[n]-ans;
printf("%I64d\n",ans);
}
return 0;
}

把所有可能的约数都预处理出来

View Code

#include<cstdio>
#include<cstring>
#define lld __int64
bool prim[10010];
lld p[10010];
lld primnum=0;
lld cntofprim[10010];
lld C4[10010];
lld cnt[10010]={0};
void init(){
int i,j;
memset(prim,0,sizeof(prim));
for(i=2;i<=10000;i++){
for(j=2*i;j<=10000;j+=i){
prim[j]=true;
}
}
for(i=2;i<=10000;i++){
if(!prim[i]){
p[primnum++]=i;
}
}
for(i=0;i<primnum;i++){
cnt[p[i]]=1;
for(j=2;j<=10000&&j*p[i]<=10000;j++){
if(j%p[i] && cnt[j])
cnt[j*p[i]] = cnt[j]+1;
}
}
for(i=2;i<=10000;i++)
if(cnt[i])
cnt[i]=(cnt[i]&1) ? 1 : -1;
for(i=4;i<=10000;i++)
C4[i]=(lld)(i*(i-1)/2)*(i-2)/3*(i-3)/4;
}
int main(){
init();
__int64 n,a,i,j,k;
while(scanf("%I64d",&n)!=EOF){
int Max=0;
memset(cntofprim,0,sizeof(cntofprim));
for(i=0;i<n;i++){
scanf("%I64d",&a);
if(a>Max) Max = a;
cntofprim[a]++;
for(j=2;j*j<=a;j++){
if(a%j==0){
cntofprim[j]++;
if(j*j!=a){
cntofprim[a/j]++;
}
}
}
}
if(n<4) {
printf("0");
continue;
}
lld sum=0;
for(i=2;i<=Max;i++){
if(cnt[i]==0) continue;
sum+=cnt[i]*C4[cntofprim[i]];
}
printf("%I64d\n",C4[n]-sum);
}
return 0;
}

 

抱歉!评论已关闭.