codeforce 461DIV2 F题

本文针对一道CF题目进行了解析,利用欧拉筛法的思想来寻找符合条件的子集,使得(a,b)对的数量等于给定值k,其中a<b且b能被a整除。文章详细介绍了实现过程及核心代码。

题意

  题目给出n,k,要求找出一个1到n的子集,(a,b)的对数等于k;(a,b)满足a<b且b%a==0;

分析

  还记不记得求素数的时候的欧拉筛!对就那样!如果把每个数字看作一个点的话,可以通过欧拉筛的方法求入度,然后想一想筛的时候j是如何增加的,可以n/i-1直接求出出度。知道这个结论这个题就不难了。先找到一个范围中,他的边数大于等于k,然后在这个范围内尝试删掉结点是否符合要求。(注意当i>n/2时,在n的范围内就没有出度了,所以可以确定,当在某个范围内边数大于等于k,一点可以通过删除某些结点使边数刚好达到k)。题解的最后那一部分我没有看懂(英语渣智商渣),但是通过这种方法确实可以在cf上A掉这个题;

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include <vector>
 6 using namespace std;
 7 const int maxn=300000+100;
 8 int d[maxn];
 9 int n;
10 long long k;
11 int main(){
12     cin>>n>>k;
13     long long sum=0;
14     for(int i=1;i<=n;i++){
15         for(int j=2*i;j<=n;j+=i){
16             d[j]++;
17             sum++;
18         }
19     }
20     if(sum<k){
21             printf("No");
22             return 0;
23     }
24     else
25         printf("Yes\n");
26     long long ps=0;
27     for(int i=1;i<=n;i++){
28         ps+=d[i];
29         if(ps>=k){
30             n=i;
31             break;
32         }
33     }
34     vector<int>ans;
35     for(int i=1;i<=n;i++){
36         int degree=d[i]+(n/i)-1;
37         if(ps-degree<k){
38             ans.push_back(i);
39             continue;
40         }
41         ps-=degree;
42         for(int j=2*i;j<=n;j+=i){
43             if(d[j])d[j]--;
44         }
45     }
46     printf("%d\n",ans.size());
47     for(int i=0;i<ans.size();i++)
48         printf("%d ",ans[i]);
49 return 0;
50 }
View Code

 

转载于:https://www.cnblogs.com/LQLlulu/p/8825124.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值