Codeforces Round #500 (Div. 2) [based on EJOI]

版权声明:版权所有,转载请标明 https://blog.csdn.net/zxwsbg/article/details/81902524

链接:http://codeforces.com/contest/1013

无聊做着玩的。

目录

A.Piles with stones

B.And

题目

题解

代码

C.Photo of The Sky

题目

题解

代码

D.Chemical table

题意

题解

代码


A.Piles with stones

傻逼题


B.And

题目

          输入n和x

          给定一个数列,如果一个数列至少出现两个一样的数,那么就符合条件。

          当然了,还可以进行操作,比如把 a[i] 替换成 a[i]&x ,这样的操作可以进行无限多次。

          输出使数列符合条件需要进行的最小操作的次数。

题解

          很简单的一道题。总共就4种情况:

  1. 随你怎么换永远不符合条件,输出-1;
  2. 不用换,本来就符合条件,输出0;
  3. 需要替换掉一个数,使其与另一个没替换的相等,输出1;
  4. 需要替换掉两个数,替换后的两个数相等,输出2;

代码

#include <bits/stdc++.h>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8

typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;

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

inline void print(int x)
{
    if(x<0){ putchar('-'); x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

inline void caltime(int tt) {
	tt = clock() - tt;
    cerr << (double)tt/CLOCKS_PER_SEC << " seconds!" << endl;
}

int n,x;
int a[maxn];
map<int,int> mp;
set<int> s1,s2;

int main()
{
	cin>>n>>x;
	for(int i=0;i<n;i++) {
		read(a[i]);
		mp[a[i]]++;
	}
	if(mp.size()<n) {
		cout<<0;
		return 0;
	}
	int temp = 0;
	for(int i=0;i<n;i++) {
		int k = a[i]&x;
		s2.insert(k);
		if(k==a[i])	continue;
		if(mp[k]==1) {
			cout<<1<<endl;
			return 0;
		}
	}
	if(s2.size()<n)	{
		cout<<2;
		return 0;
	}
	cout<<-1<<endl;
	return 0;
}


C.Photo of The Sky

题目

           输入一个n,然后给出2*n个数,要求把这2*n个数任意两两组合,形成n个点对,把这些点对放在坐标系中。要求围住它们的矩形面积最小,求这个面积。

题解

         首先可以先给数组排个序。然后可以想到,一种解法的两个端点分别为(a[1],a[n],)和(a[n+1],a[2n])这样显然是符合题意的,但是却不一定是最优的,因为可能出现高和宽都很短,但由于正方形面积最大,使得它们的面积反而大了。例如1,1,2,3,4,4,4,6。

         于是,还有种思路,就是x轴的两端分别为a[1]和a[2n],高度的两段为a[i+1]和a[n+i],这样高度上正好保证有n个点组成纵坐标,且一定符合题意。

代码

#include <bits/stdc++.h>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8

typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;

int n;
ll f[maxn];

ll solve(ll a,ll b,ll c,ll d) {
	return abs(c-a)*abs(d-b);	
}

int main()
{
	cin>>n;
	for(int i=1;i<=2*n;i++) {
		scanf("%lld",&f[i]);
	}
	sort(f+1,f+2*n+1);
	ll ans = solve(f[1],f[n+1],f[n],f[2*n]);
	for(int i=1;i<n;i++) {
		ans = min(ans,solve(f[1],f[i+1],f[2*n],f[i+n]));
	}
	cout<<ans<<endl;
	return 0;
}


D.Chemical table

题意

           三个格子的元素可以生出一个格子的元素。

          现在已知有若干个有元素的格子,问最少需要多少个元素,能把所有的都填满。(新生出来的元素不能再生,但是老元素可以用多次)

题解

          我们可以用行和列做标记,如果一行已经有了一个元素,那么该元素所处的行和列都加标记。这样就出现了一个问题,如果两个元素在对角,那么不需要三个元素就会自动生成两个,这显然是不符合题意的。

          于是,我们用vector记录某一行上的点和哪些列想连,某一列上的点和哪些行相连。

          可以看作一个并查集,依次遍历每一行,把改行所有能到的地方都加标记。对于之前说的那种情况,由于不联通,所以不能一次遍历完,要2次,所以原图可以分为两个块。

代码

#include <bits/stdc++.h>
using namespace std;

#define INIT(x) memset(x,0,sizeof(x))
#define eps 1e-8

typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn = 200005;

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

inline void print(int x)
{
    if(x<0){ putchar('-'); x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

inline void caltime(int tt) {
	tt = clock() - tt;
    cerr << (double)tt/CLOCKS_PER_SEC << " seconds!" << endl;
}

int n,m,q;
vector<int> e[maxn*10];
bool vis[maxn*10];

void dfs(int x)
{
	vis[x] = 1;
	for(int i=0;i<e[x].size();i++) {
		if(!vis[e[x][i]])
			dfs(e[x][i]);
	}
}

int main()
{
	cin>>n>>m>>q;
	for(int i=0;i<q;i++) {
		int x,y;
		read(x),read(y);
		e[x].push_back(y+n);
		e[y+n].push_back(x);
	}
	int ans = 0;
	for(int i=1;i<=m+n;i++) {
		if(!vis[i]) {
			dfs(i);
			ans++;
		}
	}	
	cout<<ans-1<<endl; //结果是ans-1,如果原图只有1个块,那么就不用增加;需要自己添加的空白格子每个都单独形成一个块
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zxwsbg/article/details/81902524
今日推荐