codeforces 1300 题解(完结)

codeforces 1300 题解

A. Non-zero

你可以对数组中任何一个元素进行操作,目的让他们的加和和乘积都不为 \(0\) 。想想什么时候加和和乘积为 \(0\)

  • 若数组中有至少一个 \(0\) ,则数组乘积为 \(0\)
  • 若数组中正负加和互为相反数,则数组加和为 \(0\) ,否则不为 \(0\)

则若想让数组乘积不为 \(0\) ,则首先需要杀灭数组中所有的 \(0\),这是肯定必要且不可少的操作。完成以后检验数组加和是否为 \(0\),若为 \(0\) 则用一个操作将数组中随便一个数进行 \(+1\) 操作,打破平衡即可。

时间复杂度 \(O(n)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 10039
#define maxe 100039
#define X first
#define Y second


int main()
{
	ios::sync_with_stdio(false);
	int t, n;
	cin >> t;
	while(t--)
	{
		cin >> n;
		int sum = 0, pro = 1;
		int zocnt = 0;
		_for(i,0,n)
		{
			int tmp;
			cin >> tmp;
			sum += tmp;
			if(!tmp)
				zocnt ++;
		}
		sum += zocnt;
		if(!sum)
			zocnt ++;
		printf("%d\n",zocnt);
	}
	return 0;
}

B. Assigning to Classes

我们将原问题转化一下,他要两个数组的中位数绝对值最小,但是这两个数组都是从原数组分出去的,因此转化一下问题就是在原数组中找两个数作为两个数组的中位数,让他们的绝对值最小,也就是在原数组中找两个可以成为分出去后的中位数的绝对值最小。

绝对值怎么最小?自然是排序后越靠近越小!那怎么选才算是合法的呢?(可以让选中的两数成为两数组中位数)

对于原数组 \(a_1,a_2,a_3...a_{2n-1},a_{2n}\) ,我们将其从小到大排序为 \(b_1,b_2,b_3...b_{2n-1},b_{2n}\) 。若选择一个元素下标为 \(i\in[1,n]\) 则可证明只有选择元素下标为 \(i==n+1\) 的元素,这样两个元素才能成为两数组中位数。同理,若选择一个元素下标为 \(i\in[n+1,2n]\) 则可证明只有选择元素下标为 \(i==n\) 的元素,这样两个元素才能成为两数组中位数。

现在再考虑选哪两个。选 \(i==1\)\(i==n+1\) ?还是说别的什么?既然 \(i==n\)\(i==n+1\) 必选其一,那就只剩下 \(\{n-1,n\}\) \(\{n,n+1\}\) \(\{n+1,n+2\}\) 这三种可能了,因为要绝对值最小嘛!细细一想第一种和第三种也不符合刚刚我们说的合法性规则,所以答案只可能是 \(\{n, n+1\}\)

时间复杂度 \(O(nlogn)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 200039
#define X first
#define Y second

int a[maxn];
int main()
{
	ios::sync_with_stdio(false);
	int t, n;
	cin >> t;
	while(t--)
	{
		cin >> n;
		n*=2;
		_for(i,0,n)
			cin >> a[i];
		sort(a,a+n);
		printf("%d\n",abs(a[n/2]-a[n/2-1]));
	}
	return 0;
}

C. Anu Has a Function

这个函数啊

\[f(x,y)=(x|y)-y=x\&(\sim y) \]

事前不知道又推不出来就比较难受了。不过知道以后就蛮好做的,原式可以写成 \(a_1 \& (\sim a_2) \& \dots (\sim a_n)\) ,因为与操作满足交换律,所以其实就是确定第一个元素是哪个就行了。预处理出前后缀,然后枚举 \(a_1\) 即可。

时间复杂度 \(O(n)\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define _for(i,a,b) for(int i = (a);i < b;i ++)
#define _rep(i,a,b) for(int i = (a);i > b;i --)
#define INF 0x3f3f3f3f
#define ZHUO 11100000007
#define MOD 1000000007
#define MIKUNUM 39
#define pb push_back
#define debug() printf("Miku Check OK!\n")
#define maxn 200039
#define X first
#define Y second

int a[maxn];
int prefix[maxn];
int suffix[maxn];
int main()
{
	ios::sync_with_stdio(false);
	int n;
	cin >> n;
	_for(i,1,n+1)
		cin >> a[i];
	prefix[1] = ~a[1];
	_for(i,2,n+1)
		prefix[i] = prefix[i-1]&~a[i];
	suffix[n] = ~a[n];
	_rep(i,n-1,0)
		suffix[i] = suffix[i+1]&~a[i];
	
	int firele = 1;
	int ans = 0;
	_for(i,1,n+1)
	{
		int tmpans = a[i];
		if(i>1)
			tmpans &= prefix[i-1];
		if(i<n)
			tmpans &= suffix[i+1];
		if(tmpans>ans)
		{
			firele = i;
			ans = tmpans;
		}
	}
	printf("%d ",a[firele]);
	_for(i,1,n+1)
		if(i!=firele)
			printf("%d ",a[i]);
	return 0;
}

D. Aerodynamic && E. Water Balance

计算几何,交给队友了。

posted @ 2020-02-10 11:24  Asurudo  阅读(385)  评论(0编辑  收藏  举报