Codeforces Round #519 by Botan Investments F. Make It One

https://codeforces.com/contest/1043/problem/F

题意

给你n个数,求一个最小集合,这个集合里面数的最大公因数等于1

1<=n<=3e5

1<=a[i]<=3e5

思路

  • 先考虑什么情况下满足集合中的最大公因数=1?
  • 集合中的每个数没有共同的素因子,即所有素因子并没有包含于选出集合的所有数中,存在结论前7个素因子的乘积为510510,所以可以得出选出的集合大小最大为7
  • 定义dp[i][j]为,集合大小为i,集合最大公因数=j的方案数
  • dp[i][j]= \(\begin{pmatrix} cnt[j] \\ i \\ \end{pmatrix}\) - \(\sum_{k=2}^{\infty}\)dp[i][j*k]

处理

  • 逆元打表求组合数
  • log(3e5)时间处理出每个数的倍数个数cnt[i]
  • 从后往前扫求dp[i][j]
#include<bits/stdc++.h>
#define ll long long

using namespace std;
const int P =1e9+7;
const int M =3e5+5;

ll F[M],Finv[M],inv[M],dp[20][M],cnt[M];
int n,x,i,j,k;

void init(){
    F[1]=Finv[1]=inv[1]=Finv[0]=inv[0]=1;
    for(int i=2;i<M;i++)inv[i]=inv[P%i]*(P-P/i)%P;

    for(int i=2;i<M;i++){
        Finv[i]=Finv[i-1]*inv[i]%P;
        F[i]=F[i-1]*i%P;
    }
}

ll C(int n,int m){
    if(m<0||n<m)return 0;
    if(m==0||n==m)return 1;
    return F[n]*Finv[n-m]%P*Finv[m]%P;
}

int main(){
    init();
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        cin>>x;cnt[x]++;
    }
    for(i=1;i<M;i++)
        for(j=i+i;j<M;j+=i)
            cnt[i]+=cnt[j];

    for(i=1;i<=15;i++){
        for(j=M-1;j>=1;j--){
            dp[i][j]=C(cnt[j],i);
            for(k=j+j;k<M;k+=j){
                dp[i][j]=(dp[i][j]-dp[i][k]+P)%P;
            }
        }
        if(dp[i][1]>0){
            cout<<i;return 0;
        }
    }
    cout<<-1;
}

原文地址:https://www.cnblogs.com/VIrtu0s0/p/9876617.html

时间: 2024-10-10 12:24:28

Codeforces Round #519 by Botan Investments F. Make It One的相关文章

Codeforces Round #519 by Botan Investments

开个新号打打codeforces(以前那号玩废了),结果就遇到了这么难一套.touristD题被卡掉了(其实是对cf的评测机过分自信),G题没过, 700多行代码,码力惊人. 做了4道,本来想着上蓝名的.然后我第二题挂了,判断循环节写错了.绝望啊---- 比赛传送门:http://codeforces.com/contest/1043 A. Elections 这题很简单,就是说有n个人,每人投k张票,给你或你对手.第i个人会给你的对手投ai票,让你求最少的k.使得你的票数比你的对手多.模拟一下

Codeforces Round #541 (Div. 2) (A~F)

目录 Codeforces 1131 A.Sea Battle B.Draw! C.Birthday D.Gourmet choice(拓扑排序) E.String Multiplication(思路) F.Asya And Kittens(链表) G.Most Dangerous Shark Codeforces 1131 比赛链接 hack一个暴力失败了两次最后还是没成功身败名裂= = CF跑的也太快了吧... 不过倒也涨了不少. A.Sea Battle //想麻烦了,但是无所谓... #

Codeforces Round #496 (Div. 3)A~F

(寒假训练赛,也是lj难得补完的一场 https://codeforces.com/contest/1005 A.题意是  每一个楼梯有x个台阶,小女孩爬楼的时候会从1开始数每层楼有几个台阶,现在给给出n个数字a1~an,代表着小女孩爬楼时数数的序列,求有多少层楼梯,并且输出每层楼梯台阶数. 解法:for循环模拟小女孩从1开始数,数到下一个1的话楼层++,然后把他前一个数存进去. int now = 0; for(int i = 0;i < n;++i){ cin>>a; if(a ==

Codeforces Round #516 (Div. 2) (A~F)

目录 A.Make a triangle! B.Equations of Mathematical Magic C.Oh Those Palindromes D.Labyrinth(BFS) E.Dwarves,Hats and Extrasensory Abilities(交互 二分) D.Labyrinth E.Dwarves,Hats and Extrasensory Abilities 比赛链接 A.Make a triangle! 不放了. B.Equations of Mathema

[题解]Codeforces Round #519 - D. Mysterious Crime

[题目] D. Mysterious Crime [描述] 有m个n排列,求一共有多少个公共子段. 数据范围:1<=n<=100000,1<=m<=10 [思路] 对于第一个排列来说,如果第k个位置开始往后L长的子段是一个公共的子段,那么从k开始往后数1,2,...,L-1长的子段都是公共的子段:如果第k个位置开始往后L长的子段是一个公共的子段,但第k个位置开始往后L+1长的子段不是一个公共的子段,那么位置k到位置k+L中任一位置j开始往后直到位置k+L的子段都不是公共的子段.这就

Codeforces Round #519 D - Mysterious Crime

题目 题意: 在m组数,每组有n个数(数的范围1-n)中,找到某些序列 使它是每组数的一个公共子序列,问这样的某些序列的个数? 思路: 不难想出答案ans是≥n的. 创立一个next数组,使每组中第i个数的next 是第i+1个数,即 nex[ a[i] ] = a[ i+1 ] (实际上设next是二维数组).对第一组中的第i个数,如果在其余每组的next[ a[ i ] ]都是等于第一组中a[ i+1 ]的,意味着序列 a[ i ],a[ i+1 ]是一个公共子序列.       利用一个数

Educational Codeforces Round 23 F. MEX Queries(线段树)

题目链接:Educational Codeforces Round 23 F. MEX Queries 题意: 一共有n个操作. 1.  将[l,r]区间的数标记为1. 2.  将[l,r]区间的数标记为0. 3.  将[l,r]区间取反. 对每个操作,输出标记为0的最小正整数. 题解: hash后,用线段树xjb标记一下就行了. 1 #include<bits/stdc++.h> 2 #define ls l,m,rt<<1 3 #define rs m+1,r,rt<&l

Educational Codeforces Round 25 F. String Compression(kmp+dp)

题目链接:Educational Codeforces Round 25 F. String Compression 题意: 给你一个字符串,让你压缩,问压缩后最小的长度是多少. 压缩的形式为x(...)x(...)  x表示(...)这个出现的次数. 题解: 考虑dp[i]表示前i个字符压缩后的最小长度. 转移方程解释看代码,这里要用到kmp来找最小的循环节. 当然还有一种找循环节的方式就是预处理lcp,然后通过枚举循环节的方式. 这里我用的kmp找的循环节.复杂度严格n2. 1 #inclu

Educational Codeforces Round 24 F. Level Generation(三分)

题目链接:Educational Codeforces Round 24 F. Level Generation 题意: 给你n个点,让你构造ans条边,使得这ans条边中至少有一半是桥. 让你求ans的最大值. 题解: 首先我们将每一个点按顺序连起来,那么可以构成n-1个桥. 然后我们可以把其中的x个点拿出来连边,这些边都不是桥. x个点最多能连x*(x-1)条边,然后剩下的n-x个点连的边将会构成桥. 然后就可以构造一个函数关系,详见check函数,然后三分一下就行了. 1 #include