烹饪 [容斥]

烹饪

题目描述见链接 .


\color{red}{正解部分}

{bi}\{b_i\} 中存在能够 凑出 11 的数字, 则可以凑出所有数字 .

于是考虑哪些数字可以凑出 11,
22 个数字 x,yx,y, ax+by=1ax + by = 1 有解的前提是 gcd(i,j)=1gcd(i, j) = 1, 推广到更多数字 kiai=1\sum k_ia_i = 1 有解的前提是 gcd(ki)=1gcd(k_i)=1.

于是 题目转化 为: 求出有多少种选数方法, 满足 gcd(b1,b2...bm)=1gcd(b_1, b_2...b_m)=1 .

考虑 容斥, 设 F[i]F[i] 表示满足以 iigcdgcd 的选出序列的个数,
F[i]F[i] 初值2cnti12^{cnt_i}-1, 减去所有 F[ki,kZ]F[ki, k \in Z] 即可得到 gcd=igcd = i 的序列数, 最后 F[1]F[1] 即为答案 .


\color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

const int maxn = 3005;
const int mod = 998244353;

int N;
int Max_v;
int A[maxn];
int F[maxn];
int pw[maxn];

int main(){
        N = read(); pw[0] = 1;
        for(reg int i = 1; i < maxn; i ++) pw[i] = 2ll*pw[i-1] % mod;
        for(reg int i = 1; i <= N; i ++) A[i] = read(), Max_v = std::max(Max_v, A[i]);
        for(reg int i = Max_v; i >= 1; i --){
                int cnt = 0;
                for(reg int j = 1; j <= N; j ++) cnt += (A[j]%i == 0);
                F[i] = pw[cnt] - 1;
                for(reg int j = 2*i; j <= Max_v; j += i) F[i] -= F[j], F[i] = (F[i]%mod+mod)%mod;
        }
        printf("%d\n", F[1]);
        return 0;
}
posted @ 2019-10-05 21:18  XXX_Zbr  阅读(109)  评论(0编辑  收藏  举报