798D的二维贪心与C的思维

http://codeforces.com/contest/798/problem/D



题目大意:

    给你两个数组长度为n的数组a,b,让你从中选择n/2+1个下表,使得对于每个数组,选择的元素之和的二倍大于整个数组的元素之和。


解题思路:

    首先,对于题目要求的选择元素之和两倍大与所有元素之和,我们可以转化为选择元素之和大于剩下的。然后我们可以将下标按照a从大到小排序。然后选择第一个,之后每两个一组,选择b大的一个,如果n是偶数再选择最后一个。

    至于这样写的正确性:首先对于数组b,每一组选择的都是大的,而且还有多选的,所以一定比剩下的大。对于数组a,从第一个开始看,当前选择的,一定比下一组剩下的a大。所以这样贪心就一定正确。

    总结一下就是,对于二维的贪心我们可以先让它变成其中一维有序,这样只需要重点考虑另一维,就会简单很多。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 10;
int a[maxn];
int b[maxn];
int n;
int p[maxn];
bool cmp(const int  &x, const int & y)
{
	return a[x] > a[y];
}
int main()
{
	while (scanf("%d", &n) != EOF)
	{
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &b[i]);
		}
		for (int i = 1; i <= n; i++)
			p[i] = i;
		sort(p + 1, p + n + 1, cmp);
		printf("%d\n", n / 2 + 1);
		printf("%d", p[1]);
		for (int i = 2; i < n; i += 2)
		{
			int x = p[i], y = p[i + 1];
			if (b[x] > b[y])
				printf(" %d", x);
			else printf(" %d", y);
		}
		if (n % 2 == 0)
			printf(" %d", p[n]);
		cout << endl;
	}
	return 0;
}


http://codeforces.com/contest/798/problem/C


转载自:


http://blog.csdn.net/harlow_cheng/article/details/70344529


题意】 

给你n个数字; 
要求你进行若干次操作; 
每次操作对第i和第i+1个位置的数字进行; 
将 
a[i]变为a[i]-a[i+1],a[i+1]变为a[i]+a[i+1]; 
然后问你能不能通过以上变换使得最后所有元素的gcd>1 

【题解】 

答案总是存在的; 
因为把这个操作进行两次可以得到-2*a[i+1],2*a[i] 
也就是如果对每相邻的元素进行操作,最后都能使得这两个元素都变成偶数; 
最后gcd最少都为2了; 
则: 
如果一开始所有元素的gcd>1则直接输出0; 
等于1; 
假设改变一次后的gcd为d 
则d|a[1..i-1]且d|a[i+2..n] 
且d|a[i]-a[i+1]且d|a[i]+a[i+1] 
因为由d|x和d|y可以得到 
d|x+y以及d|x-y 
所以 
d|2*a[i]且d|2*a[i+1] 
这样就大概猜测要使得每个元素都变成偶数吧. 
每个元素都贪心地让他变成偶数就好了; 
(有了“这个操作进行两次可以得到-2*a[i+1],2*a[i]”这个结论,我们可以放心地进行贪心,当然不一定是都要进行两次操作,比如a[i]和a[i+1]都是奇数,则只要进行一次操作,因为一次操作后两个数的奇偶性都会因为加、减了一个奇数而发生改变); 
只要第i个元素没有变成偶数就一直进行这个操作; 
然后第n个元素如果最后在前n-1个元素进行操作之后没有变成偶数; 
则必然可以对n-1,n操作两次使得a[n-1]保留仍旧是偶数,a[n]也变成了偶数; 
因为 
a[n-1]是偶数了,a[n]是奇数 
第一次操作后 
a[n-1]变成奇数,a[n]还是奇数; 
再进行一次操作后 
a[n-1]变成偶数,a[n]也变成偶数; 
具体看代码 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100000 + 10;
typedef long long ll;
int a[maxn];

int gcd(int x, int y)
{
	return y ? gcd(y, x%y) : x;
}
int n;

int  main()
{
	while (~scanf("%d", &n))
	{
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		int c = a[1];
		for (int i = 2; i <= n; i++)
		{
			c = gcd(c, a[i]);
		}
		puts("YES");
		if (c > 1)
		{
			cout << 0 << endl;
			continue;
		}
		int ans = 0;
		for (int i = 1; i <= n; )
		{
			if (a[i] % 2 == 0)
			{
				i++;
				continue;
			}
			int j = i;
			while (a[j] % 2 && j <= n)
			{
				j++;
			}
			if ((j - i) % 2 == 0)
				ans += (j - i) / 2;
			else ans += (j - i) / 2 + 2;
			i = j;
		}
		cout << ans << endl;
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值