题目链接:https://ac.nowcoder.com/acm/contest/548/F
题意:简化题意之后就是求[1,n]中不能被[2,m]中的数整除的数的个数。
思路:简单容斥题,求[1,n]中不能被[2,m]中的数整除的数的个数,可以通过求能够被整除的数。
首先,[2,m]中的合数肯定能由[2,m]中的素数的乘积来表示,所以我们仅需要考虑[1,n]中能由[2,m]中的素数整除的数的个数即可,记为sum。
然后,我们知道[1,n]中能够被x整除的数的个数为n/x(向下整除)。
then,如果按上一步计算的话,会出现重复计算的问题,这个时候就用到了容斥原理,若[2,m]有p个素数,分别为cnt[1]..cnt[p],那么这p个素数可以有(1<<p)-1个组合,记该组合中所有素数乘积为tmp,素数个数为num,则能被tmp整除的数有(n/tmp)个,若num为奇数,则sum加上(n/tmp),若为偶数,则sum减上(n/tmp),这样就解决了问题。还有本题要注意的一个小细节是若k==0,直接输出QAQ即可。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 int T,m,cnt[10]={0,2,3,5,7,11,13,17,19}; 6 int M[25]={0,0,1,2,2,3,3,4,4,4,4,5,5,6,6,6,6,7,7,8,8}; 7 LL k,q,n,sum; 8 9 int main(){ 10 scanf("%d",&T); 11 while(T--){ 12 scanf("%lld%lld%lld%d",&k,&q,&n,&m); 13 int p=M[m]; 14 sum=0; 15 for(int i=1;i<(1<<p);++i){ 16 int num=0; 17 LL tmp=1; 18 for(int j=1;j<=p;++j) 19 if((1<<(j-1))&i){ 20 ++num; 21 tmp*=cnt[j]; 22 } 23 if(num&1) 24 sum+=n/tmp; 25 else 26 sum-=n/tmp; 27 } 28 sum=(n-sum)+k-1; 29 if(sum>n) sum=n; 30 if(k&&sum>=q) printf("Yes "); 31 else printf("QAQ "); 32 } 33 return 0; 34 }