ZJUT1522 How many choices 容斥原理

本文介绍了一种使用容斥原理解决ACM竞赛中特定数学问题的方法,并提供了详细的算法思路及实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Address:http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1522

 

容斥原理。很轻松就AC掉。

 

但是另一道题——此题M为10^4,另一道题M为10^9——却总也A不掉。

 

以下是1522的代码:

 

#include <iostream>
using namespace std;
int main()
{
 bool *num = (bool*)malloc(sizeof(bool)*10000+1);
 int n,m,i,j,x;
 while(scanf("%d %d", &n, &m)!=EOF)
 {
  memset(num, false, sizeof(bool)*m+1);
  for (i=0; i<n; i++)
  {
   scanf("%d", &x);
   for (j=x; j<=m; j=j+x)
   {
    num[j] = true;
   }
  }
  for (x=0,i=1; i<=m; i++)
  {
   if (!num[i]) x++;
  }
  printf("%d/n", x);
 }
 free(num);
 return 0;
}

 

后来想了一下,可以求出n个数的最小公倍数,然后计算公倍数以内的数再去做适当的运算即可。试了有一阵子,在1522过了,但是另一道还是不行。老是MLE。哎

 

以下是计算出最小公倍数的代码:

 

#include <iostream>
using namespace std;
double gcd(double a, double b)
{
 int t,z;
 double x=a, y=b;
 if (a<b)
 {
  t = a;
  a = b;
  b = t;
 }
 while(b!=0)
 {
  z = a/b;
  t = a-z*b;
  a = b;
  b = t;
 }
 return x/a*y;
}
int main()
{
 bool *num;
 double min,mintemp;
 int n,m,i,j,x[15],out,mul,ct;
 while(scanf("%d %d", &n, &m)!=EOF)
 {
  min = 1;
  for (i=0; i<n; i++)
  {
   scanf("%d", &x[i]);
   min = gcd(min, (double)x[i]);
  }
  if (min>(double)m) min=m;
  mintemp = (int)min;
  num = (bool*)malloc(sizeof(bool)*mintemp+1);
  memset(num, false, sizeof(bool)*mintemp+1);
  for (i=0; i<n; i++)
  {
   for (j=x[i]; j<=mintemp; j=j+x[i])
   {
    num[j] = true;
   }
  }
  mul = m/mintemp;
  out = m-mul*mintemp;
  ct = 0;
  for (i=1; i<=mintemp; i++)
  {
   if (!num[i]) ct++;
  }
  ct *= mul;
  for (i=1; i<=out; i++)
  {
   if (!num[i]) ct++;
  }
  printf("%d/n", ct);
  free(num);
 }
 return 0;
}

 

明天再想了= =

 

++++++++++++++++++++++++++++++++++++++++++++++时间分隔线

 

今天早上起床,坐在床上想了一会,想出了一个方法。

 

发现这才是真正的容斥原理啊!!

 

思路就是把每一个数的最小公倍数的m以内的倍数的个数加起来。

 

然后把每两个数的最小公倍数的m以内的倍数的个数减掉。

 

然后把每三个数的最小公倍数的m以内的倍数的个数加起来。

 

……

 

到最后就是所求答案了。

 

DEBUG之后提交,一次AC,哈哈!

 

 

p.s.发现原来代码是这样插入的啊,哈哈哈哈哈!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值