zoukankan      html  css  js  c++  java
  • CF 888E Maximum Subsequence

    一道比较套路的题,看到数据范围就差不多有想法了吧。

    题目大意:给一个数列和(m),在数列任选若干个数,使得他们的和对(m)取模后最大

    取膜最大,好像不能DP/贪心/玄学乱搞啊。(nle35)?果断meet in middle

    考虑我们已经搜出了序列前一半的解,那么怎么根据后面的结果合并出结果?

    设我们现在得到的和为(x)(对(m)取膜后),我们令一个数(y=m-x),然后在前面的解中查找(y)的前驱即可

    接下来进行简单的证明:

    • 若可以找到前驱(z),由于(z<y),故(x+z<m)。又因为(z=max(sin[1,y-1])),故此时值最大。
    • 若无法找到前驱(z),此时我们取任何一个值(s)都会导致(x+s>x+y=m),此时((x+s) mod m<x)(这个很好理解吧)

    于是我们每次都二分找出前缀,并取(max)即可。

    CODE

    #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;
    }
    
  • 相关阅读:
    Linux环境定时备份mysql数据库
    idea以DEBUG方式启动项目卡住,但是不报错
    Linux查看防火墙,开放端口
    element动态添加删除表格的行数
    触发器编写,执行插入或update分别执行不同sql
    vue数组判断数值,遍历,过滤
    将某文件夹下的文件压缩成zip
    转载:win10专业版取消自动更新
    IIS启动应用程序池报错"服务无法在此时接受控制信息
    IIS7 设置网站默认主页(首页)
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9426866.html
Copyright © 2011-2022 走看看