• LG P6570 [NOI Online #3 提高组]优秀子序列


    Description

    给定一个长度为 $n$ 的非负整数序列 $A={a_1,a_2,cdots,a_n}$,对于 $A$ 的一个子序列 $B={a_{b_1},a_{b_2},cdots,a_{b_m}}$($0le mle n$,$1le b_1 < b_2 < cdots < b_mle n$,下同),称 $B$ 是 $A$ 的优秀子序列当且仅当,其任意两个不同元素的按位与结果均为 $0$,即:$forall 1le i < jle m$,满足:$a_{b_i}~mathrm{and}~a_{b_j}=0$,其中 $~mathrm{and}~$ 是按位与运算。

    对于子序列 $B={a_{b_1},a_{b_2},cdots,a_{b_m}}$,我们定义其价值为 $varphi(1+sum_{i=1}^m a_{b_i})$,其中 $varphi(x)$ 表示小等于 $x$ 的正整数中与 $x$ 互质的数的个数。

    现在请你求出 $A$ 的所有优秀子序列的价值之和,答案对 $10^9+7$ 取模。

    Solution

    如果将每个数视为$2$的幂次的集合,那么题目就是要求$sum_{x in S}x$,$S$是一个合法序列

    因为$2$的幂次相加不会进位,上式就是$cup_{x in S}x$

    设$dp_i$表示合法序列中所有元素并为$i$的方案数

    那么题中所求即为

    $$sum dp_x varphi(x+1)$$

    $varphi$可以一次线性筛求出,$dp$可以一次子集DP求出

    最后加上空集

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    long long n,maxx,tot,m;
    long long dp[400005]={1},phi[400005],buc[400005],prime[400005],a[1000005],ans=1;
    bool vst[400005];
    const long long mod=1e9+7;
    inline long long read()
    {
        long long f=1,w=0;
        char ch=0;
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
        return f*w;
    }
    void pre(long long N)
    {
        phi[1]=1;
        for(long long i=2;i<=N;i++)
        {
            if(!vst[i]) prime[++tot]=i,phi[i]=i-1;
            for(long long j=1;j<=tot&&i*prime[j]<=N;j++)
            {
                vst[i*prime[j]]=true;
                if(!(i%prime[j]))
                {
                    phi[i*prime[j]]=phi[i]*prime[j];break;
                }
                else phi[i*prime[j]]=phi[i]*phi[prime[j]];
            }
        }
    }
    int main()
    {
        n=read();
        for(long long i=1;i<=n;i++) a[i]=read(),maxx=max(maxx,a[i]),buc[a[i]]++;
        while((1<<m)<=maxx) m++;
        pre(1<<m);
        for(long long i=1;i<=(1<<m);i++)
        {
            for(long long s=i;;s=(s-1)&i)
            {
                long long t=i^s;
                if(s<t) break;
                (dp[i]+=dp[t]*buc[s]%mod)%=mod;
            }
            (ans+=dp[i]*phi[i+1]%mod)%=mod;
        }
        for(long long i=1;i<=buc[0];i++) (ans*=2)%=mod;
        printf("%lld
    ",ans);
        return 0;
    }
    优秀子序列
  • 相关阅读:
    idea使用之myeclipse项目迁移到idea
    启用Windows10的Linux子系统并安装图形界面
    Structs2+spring+hibernate+JPA整合
    微信小程序 跳转页面
    flutter 环境配置
    微信小程序 接口改为promise 由异步改为同步解决多层异步回调
    微信小程序 canvas绘制图片并下载
    微信小程序授权认证 操作
    html5 移动端页面软键盘弹出影响页面布局
    js移动端软件盘弹出隐藏处理
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14052090.html
Copyright © 2020-2023  润新知