• Solution -「CF 888E」Maximum Subsequence


    Description

    Link.

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

    Solution

    记录一下犯下的一个 nt 错误。

    首先我们有一个显然的 DFS 暴力,每次两种决策,选或不选,所以时间复杂度为 (Theta(2^{n}))

    (n) 的范围是 35,是过不了的,我们可以考虑折半搜索。

    关于折半搜索可以看看 我的折半搜索小计

    暴力搜出 ([1,lfloorfrac{n}{2} floor],[lfloorfrac{n}{2} floor+1,n]) 的所有答案,记录到两个 vector 里面。

    这一部分的时间复杂度是 (Theta(2^{lfloorfrac{n}{2} floor}))

    考虑合并贡献。

    先考虑一个暴力合并贡献的方法。

    我们记第一次搜索搜出来的答案序列为 (A_{1}),同理有 (A_{2})

    这里的两个答案序列都是在模 (m) 意义下的。

    那么对于每一个 (A_{1,i}),我们都可以暴力在 (A_{2}) 中寻找两者相加模 (m) 的最大值。

    那么我们可以分类讨论了,因为序列在模 (m) 意义下,所以我们对于每一个 (A_{1,i}) 找到的 (A_{2,j}) 使得 ((A_{1,i}+A_{2,j})mod m) 最大,都只有两种情况。

    一种是 (A_{2,j})(A_{2}) 中值域范围在 ([0,m-A_{1,i}-1]) 的所有值中最大,一种是在 (A_{2}) 中值域范围在 ([0,m imes2-A_{1,i}-1]) 的所有值中最大。

    所以我们在这两种情况中取最大即可。

    由于我不理解二分做法,所以我用的是动态开点值域线段树。

    (flag:动态开点不加引用就【】)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=35+5;
    const int H=99999999;
    int n,m,tot=1,root=1,ans,a[N];
    struct Tree
    {
    	int ls,rs,val;
    } nodes[(1<<(N>>1))<<3];
    vector<int> vec[2];
    
    void dfs(int x,int cur,int lim)
    {
    	if(x>lim)
    	{
    		if(lim==(n>>1)) 	vec[0].push_back(cur);
    		else	vec[1].push_back(cur);
    		return ;
    	}
    	dfs(x+1,(cur+a[x])%m,lim);
    	dfs(x+1,cur,lim);
    }
    
    void ins(int &p,int l,int r,int x)
    {
    	if(p==0)	p=++tot;
    	if(l==r)
    	{
    		nodes[p].val=l;
    		return ;
    	}
    	int mid=(l+r)>>1;
    	if(mid>=x)	ins(nodes[p].ls,l,mid,x);
    	else	ins(nodes[p].rs,mid+1,r,x);
    	nodes[p].val=max(nodes[nodes[p].ls].val,nodes[nodes[p].rs].val);
    }
    
    int find(int p,int l,int r,int x,int y)
    {
    	if(l>y||r<x)	return 0;
    	if(l>=x&&r<=y)	return nodes[p].val;
    	int mid=(l+r)>>1,ret=0;
    	if(mid>=x)	ret=max(ret,find(nodes[p].ls,l,mid,x,y));
    	if(mid<y)	ret=max(ret,find(nodes[p].rs,mid+1,r,x,y));
    	return ret;
    }
    
    void output(int p)
    {
    	if(nodes[p].ls==0&&nodes[p].rs==0)
    	{
    		printf("%d ",nodes[p].val);
    		return ;
    	}
    	output(nodes[p].ls);
    	output(nodes[p].rs);
    }
    
    signed main()
    {
    	scanf("%d %d",&n,&m);
    	for(int i=1;i<=n;++i)	scanf("%d",&a[i]);
    	dfs(1,0,n>>1);
    	dfs((n>>1)+1,0,n);
    	sort(vec[0].begin(),vec[0].end());
    	sort(vec[1].begin(),vec[1].end());
    	for(auto x:vec[1])	ins(root,0,m-1,x);
    	for(auto x:vec[0])	ans=max(ans,max(x+find(1,0,m-1,0,m-x-1),(x+find(1,0,m-1,0,m*2-x-1))%m));
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    js笔记1
    106. Construct Binary Tree from Inorder and Postorder Traversal根据后中序数组恢复出原来的树
    365. Water and Jug Problem量杯灌水问题
    452. Minimum Number of Arrows to Burst Balloons扎气球的个数最少
    650. 2 Keys Keyboard复制粘贴的次数
    249. Group Shifted Strings把迁移后相同的字符串集合起来
    450. Delete Node in a BST 删除bst中的一个节点
    528. Random Pick with Weight index的随机发生器
    582. Kill Process杀死所有子代
    348. Design Tic-Tac-Toe设计井字游戏
  • 原文地址:https://www.cnblogs.com/orchid-any/p/13708110.html
Copyright © 2020-2023  润新知