CF 888E Maximum Subsequence

一道比較套路的題,看到數據範圍就差很少有想法了吧。git

題目大意:給一個數列和\(m\),在數列任選若干個數,使得他們的和對\(m\)取模後最大spa

取膜最大,好像不能DP/貪心/玄學亂搞啊。\(n\le35\)?果斷meet in middlecode

考慮咱們已經搜出了序列前一半的解,那麼怎麼根據後面的結果合併出結果?it

設咱們如今獲得的和爲\(x\)(對\(m\)取膜後),咱們令一個數\(y=m-x\),而後在前面的解中查找\(y\)的前驅便可io

接下來進行簡單的證實:class

  • 若能夠找到前驅\(z\),因爲\(z<y\),故\(x+z<m\)。又由於\(z=max(s\in[1,y-1])\),故此時值最大。
  • 若沒法找到前驅\(z\),此時咱們取任何一個值\(s\)都會致使\(x+s>x+y=m\),此時\((x+s)\ mod\ m<x\)(這個很好理解吧)

因而咱們每次都二分找出前綴,並取\(max\)便可。數據

CODEsort

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int N=40;
int a[N],n,m,sum[1<<20],cnt,ans;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline int find(int x)
{
    int l=1,r=cnt,res;
    while (l<=r)
    {
        int mid=l+r>>1;
        if (sum[mid]<x) res=sum[mid],l=mid+1; else r=mid-1;
    }
    return res;
}
inline void init(int now,int tot)
{
    if (now>(n>>1)) { sum[++cnt]=tot; return; }
    init(now+1,(tot+a[now])%m); init(now+1,tot);
}
inline void DFS(int now,int tot)
{
    if (now>n) { ans=max(ans,tot+find(m-tot)); return; }
    DFS(now+1,(tot+a[now])%m); DFS(now+1,tot);
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i; read(n); read(m);
    for (i=1;i<=n;++i) read(a[i]);
    init(1,0); sort(sum+1,sum+cnt+1); DFS((n>>1)+1,0);
    return printf("%d",ans),0;
}
相關文章
相關標籤/搜索