广工oj 1231 && 51nod 1821 加强版 思维+并查集 OR 栈

16 篇文章 0 订阅
11 篇文章 0 订阅

题目链接



      这个应该是最基础的一道题目了.假设当时我们可以凑出(0,n)的所有数,那么只有当来的数x满足  

n+1 >= x 才能保证凑出新的(0,n+x)的所有的数.否则若x为n+2 那么就无法凑出n+1 等等.


所以这个题目直接排个序,然后扫一遍  直到 ans+1 <x 停止 

int a[N];
int main(){
    int _,n;
    scanf("%d",&_);
    while(_--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        sort(a+1,a+n+1);
        LL ans = 0;
        for(int i=1;i<=n;i++){
            if(ans+1>=a[i]) ans+=a[i];
            else  break;
        }

        printf("%lld\n",ans);
    }
    return 0;
}


51nod 1821


这个题目是个加强版.要使优美值最大,那么首先将集合a,先按照上述的过程找到最大值,即直到ans + 1 <x.那么我

们在从b集合中找到满足ans + 1>=x 的最大的.这样才能使新得到的ans尽可能的大从而加入更多的x 达到最大优美值.

那么问题就转化为怎么快速的在b中找到满足条件的最大的.因为每次从b开头扫会T的.

  这里肯定将所有的集合先进行了升序排序。

这里采用两个方法:

1.栈:

找到再a中的最优解后,每次将b集合中所有满足条件的解加入答案,然后每次取栈顶就是满足条件的最大的.

2.并查集

巧妙的利用并查集来维护区间.在b中找到满足条件的最后一个,如果当前他已经被使用了,那么他指向的就是它前面

第一个未被使用的,以此来实现区间的跳跃.这样每次使用完一个就把他指向前面第一个未用的,直到指向0就代表找不到

满足 ans + 1 >= x 的最优解更大的了。


这个题目的话感觉栈更好理解,并查集的应用在实现区间跨越方面也很常见.


并查集:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>

using namespace std; 
typedef long long ll;
const int maxn = 1e3 + 10;
int a[maxn][maxn];

int pre[maxn];
void init()
{
	for(int i = 0;i < maxn ;i++)
	pre[i] = i;
	return ;
}
int find(int x)
{
	return x == pre[x] ? x : pre[x] = find(pre[x]);
}

inline int read()  
{  
    char c = getchar();  
    int x = 0, f = 1;  
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}  
    while(c >= '0' && c <= '9') {x = x*10+c-'0';c = getchar();}  
    return x*f;  
}  

int main()
{
	int n;
	n = read();
	for(int i = 1;i <= n;i++)
	{
		a[i][0] = read();
		for(int j = 1;j <= a[i][0];j++)
		a[i][j] = read();
		sort(a[i] + 1,a[i] + a[i][0] + 1);
	}
	int _;
	_ = read();
	int x,y,k;
	while(_--)
	{
		x = read();
		y = read();
		k = read();
		init();
		int i = 1,j = 1,ans = 0;
		while(k--)
		{
			for(;i <= a[x][0];i++)
			{
				if(ans + 1 >= a[x][i])
				ans += a[x][i];
				else
				break;
			}
			for(; j <= a[y][0];j++)
			{
				if(a[y][j] > ans + 1)
				break;
			}
			j--;
			int f = find(j);
			if(!f)
			break;
			ans += a[y][f];
			pre[f] = find(f-1);
		}
		for(;i <= a[x][0];i++)
		{
			if(ans + 1 >= a[x][i])
			ans += a[x][i];
			else
			break;
		}
		printf("%d\n",ans);
	}
	return 0;
}


栈:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>

using namespace std; 
typedef long long ll;
const int maxn = 1e3 + 10;
int a[maxn][maxn];

inline int read()  
{  
    char c = getchar();  
    int x = 0, f = 1;  
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}  
    while(c >= '0' && c <= '9') {x = x*10+c-'0';c = getchar();}  
    return x*f;  
}  

int main()
{
	int n;
	n = read();
	for(int i = 1;i <= n;i++)
	{
		a[i][0] = read();
		for(int j = 1;j <= a[i][0];j++)
		a[i][j] = read();
		sort(a[i] + 1,a[i] + a[i][0] + 1);
	}
	int _;
	_ = read();
	int x,y,k;
	while(_--)
	{
		x = read();
		y = read();
		k = read();
		int i = 1,j = 1,ans = 0;
		stack<int>st;
		while(k--)
		{
			for(;i <= a[x][0];i++)
			{
				if(ans + 1 >= a[x][i])
				ans += a[x][i];
				else
				break;
			}
			for(; j <= a[y][0];j++)
			{
				if(a[y][j] <= ans + 1)
				st.push(a[y][j]);
				else
				break;
			}
			if(st.size())
			{
				int num = st.top();
				st.pop();
				ans += num;
			}
			else
			break;
		}
		for(;i <= a[x][0];i++)
		{
			if(ans + 1 >= a[x][i])
			ans += a[x][i];
			else
			break;
		}
		printf("%d\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marcus-Bao

万水千山总是情,只给五角行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值