牛客练习赛52 C 烹饪(容斥+扩展欧几里得)

来源:https://ac.nowcoder.com/acm/contest/1084/D
思路来源:https://www.cnblogs.com/Morning-Glory/p/11521114.html

题意

n个数,从中选一些数,使得他们通过加减法能构成任意正整数(每个数可以使用无穷多个),问有多少种方案

思路

只要选中的数中,有两个数可以构成1,就可以构成任意的正整数了
形式化的表示为选中的这一堆数中存在x,y使得\(ax+by=1\)
根据扩展欧几里得,上式当且仅当\(gcd(x,y)=1\)的时候有解
而一旦一些数中存在两个数互质,那么所有的数都互质
所以我们只需要找到所有的非空子集,使得集合里的所有数互质即可

设f[i]为gcd为i的子集个数
\(f[i]=gcd\)\((i,2i,3i,...)\)的子集个数\(-f[2i]-f[3i]-...\)
而gcd为i的倍数的子集个数为\(2^{所有i的倍数的数的个数}-1\)
答案即\(f[1]\)

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
#include<unordered_map>
    
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1

using namespace std;

typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;

const db eps = 1e-6;
const int mod = 998244353;
const int maxn = 5e5+100;
const int maxm = 2e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

int n,m;
int num[maxn];
ll po[maxn];
ll f[maxn];
int a[maxn];
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
        for(int j = 1; j<=a[i]; j++){
            if(a[i]%j==0){num[j]++;}
        }
    }
    po[0]=1;
    for(int i = 1; i <= 3000; i++)po[i]=(po[i-1]*2)%mod;
    for(int i = 3000; i >= 1; i--){
        f[i]=(po[num[i]]+mod-1)%mod;
        for(int j = 2; j*i<=3000; j++){
            f[i]=(f[i]+mod-f[j*i])%mod;
        }
    }
    printf("%lld",f[1]%mod);
    return 0;
}
posted @ 2019-09-16 17:12  wrjlinkkkkkk  阅读(168)  评论(0编辑  收藏  举报