CF888E Maximum Subsequence (Meet in the middle,贪心)

题目链接


Solution

Meet in the middle.
考虑到 \(2^{35}\) 枚举会超时,于是分成两半枚举(尽量平均).
然后不能 \(n^2\) 去匹配,需要用到一点贪心:
将数分成 \(p,q\) 两组,那么对于任意数 \(p_i\) ;
它与 \(q\) 数组中组成最大得到的值即为
最大的与 \(p_i\) 之和不超过\(m\) 的数.
然后就可以贪心优化了.
还要注意一点就是最大的两个也要考虑一次.

Code

#include<bits/stdc++.h>
#define N 1<<20
#define ll long long
using namespace std;

ll n,m,w[40],p[N],q[N],ans;
ll cntp,cntq,a[40],b[40];

void dfs1()
{
    ll num=(n+1)/2;
    for(ll i=0;i<num;i++)a[i]=w[i*2+1];
    ll tot=(1<<num)-1;
    for(ll i=1;i<=tot;i++)
    {
        ll Tot=0;
        for(ll j=0;j<num;j++)
        if((1<<j)&i)
        Tot+=a[j],Tot%=m;
        p[++cntp]=Tot;
    }
}

void dfs2()
{
    ll num=n/2;
    for(ll i=0;i<num;i++)
    b[i]=w[(i+1)*2];
    ll tot=(1<<num)-1;
    for(ll i=1;i<=tot;i++)
    {
        ll Tot=0;
        for(ll j=0;j<num;j++)
        if((1<<j)&i)
        Tot+=b[j],Tot%=m;
        q[++cntq]=Tot;
    }
}

int main()
{
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++)
    scanf("%lld",&w[i]);
    sort(w+1,w+n+1);
    dfs1(); dfs2();
    sort(p+1,p+cntp+1);
    sort(q+1,q+cntq+1);
    //for(ll i=1;i<=cntp;i++)cout<<p[i]<<' ';cout<<endl;
    //for(ll i=1;i<=cntq;i++)cout<<q[i]<<' ';cout<<endl;
    int i=0,j=cntq;
    while(i<=cntp){
        while(p[i]+q[j]>=m) --j;
        ans=max(ans,p[i]+q[j]),++i;
    }//贪心优化部分
    ans=max(ans,(p[cntp]+q[cntq])%m);
    cout<<ans<<endl;
}

posted @ 2018-10-25 20:03  Kevin_naticl  阅读(261)  评论(0编辑  收藏  举报