Nordic Collegiate Programming Contest 2017

B,模拟题目。
题意是从一堆人中选出四个人来取跑接力赛,每个人有两个值,一个是跑第一棒的时间,一个是跑除了第一棒的时间。让你选出四个人使得时间最小。
很明显考虑,暴力求解的话。枚举第一个人,让他跑第一棒,然后接着枚举剩下三个人,不与第一个人重复,然后记录下来最小的时候的名字即可。不过超时了肯定。
考虑优化一波,对于第二值我们用set维护,枚举第一个,从set中删掉自己,再取前三个,保证了second的值最小,做完再复原set就行。
注意set<pair<>>优先比较第一个。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n;
struct node {
	string name; double fi; double se;
}peo[505];
set<pair<double, int> >s;
int a, b, c, d;
double sum=1e9;
void check(int x)
{
	double ans = peo[x].fi;
	int cnt = 0;
	s.erase(make_pair(peo[x].se, x));
	for(set<pair<double, int> > ::iterator it = s.begin();cnt<3;it++)
	{
		ans += it->first;
		cnt++;
	}
	if (ans < sum)
	{
		sum = ans;
		a = x;
		set<pair<double, int> > ::iterator it = s.begin();
		b = it->second; it++;
		c = it->second; it++;
		d = it->second;
	}
	s.insert(make_pair(peo[x].se, x));
}
int main()
{
	n = read();
	up(i, 0, n)
	{
		cin >> peo[i].name >> peo[i].fi >> peo[i].se;
		s.insert(make_pair(peo[i].se, i));
	}
	up(i, 0, n)
	{
		check(i);
	}
	cout << sum << endl;
	cout << peo[a].name <<endl<< peo[b].name <<endl<< peo[c].name <<endl<< peo[d].name << endl;
}

D题。
一开始读错题目了,以为是贪心的签到题目,wa了两发,经过队友提醒发现是自己做过的牛客原题目。。。直接复制一波了代码。
题意就是让你与给出的n’个二进制字符串中,找一个等长二进制字符串,使得n个串匹配的最大值最小。
考虑bfs,我们发现,匹配的值是同或出来的值,反过来就是让异或值最小最大。我们用bfs进行层次遍历。先把初始串入队,然后每一个串,分别匹配有一个位置和自己不一样的。然后一直bfs下去直到所有n长度的串被找完了或者无法进行下去了。
这样我们可以看出,每一次往下找,就是使得异或值加一,匹配值减小。那么我们最远的层次就是我们所要找的串,因为bfs是层先,一个串能达到说明其他串至少与他的不同的值至少比现在的层次还要深,即同或值还要小。找到最远能够达到的,就是同或值最大最小的。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
int n; int k;
const int N = (1 << 22);
int vis[N];
string s;
queue<int >a;
int main()
{
	n = read();
	k = read();
	memset(vis, -1, sizeof(vis));
	up(i, 0, n)
	{
		cin >> s;
		int status = 0;
		up(j, 0, k)
		{
			if (s[j] == '1')
			{
				status |= (1 << (k - j - 1));
			}
		}
		if (vis[status] == -1)
		{
			vis[status] = 0;//自己和自己走的步数为零
			a.push(status);
		}
	}
	int ans = 0;
	while (!a.empty())
	{
		int temp = a.front();
		a.pop();
		ans = max(ans, vis[temp]);
		up(i, 0, k)
		{
			int val = temp ^ (1 << i);
			if (vis[val] == -1)//保证第一次到达
			{
				vis[val] = vis[temp] + 1;
				a.push(val);
			}
		}
	}
//	cout << ans << endl;
	int pos = -1;
	up(i, 0, N)
	{
		if (vis[i] == ans)
		{
			pos = i;
			break;
		}
	}
	//cout << pos << endl;

	string ss = "";
	dwd(i, k-1, 0)
	{
		if (pos >> i & 1)
		{
			ss += '1';
		}
		else ss += '0';
	}
	cout << ss << endl;
	return 0;
}

G题。
每个队伍有两个key值,一个是过题数目,一个是罚时,罚时累加。
现在给你q个询问,每个询问过后找出原来序号为1的队伍的位置。
这道题直接就按照题意写就好了,主要是要维护三个值,直接上不好找到stl容器。
所以就自定义一个结构体,set存放就好了。set里面放置比1大的所有队伍。
注意的就是set的定义<符号,一定=号都要有返回值,然后就是注意并列的情况和set的容器删除的情况。

#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
struct node {
	int id, nums, score;
	bool operator<(const node &a)const
	{
		if (nums != a.nums)return nums > a.nums;
		else if (score != a.score)
			{
				return score < a.score;
			}
		return id < a.id;//这样返回容易找并列的情况
	}
}team[100005];
set<node>s;
int n, m;
int main()
{
	n = read();
	m = read();
	int x,y;
	upd(i, 1, n)team[i].score = 0, team[i].nums = 0, team[i].id = i;;
	up(i, 0, m)
	{
		x = read(); y = read();
		if (x != 1)
		{
			if (s.find(team[x]) != s.end())
			{
				s.erase(team[x]);
			}
			team[x].nums++;
			team[x].score+=y;
			if (team[x] < team[1])
			{
				s.insert(team[x]);
			}
		}
		else if(x==1)
		{
			team[x].nums++;
			team[x].score += y;
			while (!s.empty()&&team[x]<*(--s.end()))
			{
				s.erase(--s.end());
			}
		}
		cout << s.size()+1 << endl;
	}
	return 0;
}

I题,每一个name,给出他能达到的所有点,判断最小环。
按照白皮书上的判环方法写的直接。用的弗洛伊德算法和链式结构储存环。注意是后项链倒序输出,在这里wa了一发。然后在更新那里忘记了记录值,wa在了49组。

#include<bits/stdc++.h>
using namespace std;
vector<int>vec;
//const int maxn=1e5+10;
long long g[520][520];
int prevv[520][520];
bool used[1000];
const long long maxn = 0x3f3f3f3f3f3f;
map<string, int>mp;
map<int, string>mp1;
void add(int u, int v)
{
	g[u][v] = 1;
}
int main()
{
	memset(g, maxn, sizeof(g));
	int n, m;
	cin >> n;
	string s, s1;
	for (int i = 0; i < n; i++)
	{
		cin >> s;
		mp[s] = i;
		mp1[i] = s;
	}
	for (int i = 0; i < n; i++)
	{
		cin >> s1;
		scanf("%d", &m);
		for (int j = 0; j < m; j++)
		{
			cin >> s;
			cin >> s;
			while (s[s.size() - 1] == ',')
			{
				//cout << s << endl;
				s.erase(s.size() - 1);
				add(mp[s1], mp[s]);
				cin >> s;
			}
			add(mp[s1], mp[s]);
		}
	}
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				prevv[i][j] = i;
		long long ans = maxn, anspos = -1;
		for (int k = 0; k < n; k++)
		{
			for (int i = 0; i < n; i++)
			{
				for (int j = 0; j < n; j++)
				{
					if (g[i][j] > g[i][k] + g[k][j])
					{
						g[i][j] = g[i][k] + g[k][j];
						prevv[i][j] = prevv[k][j];
					}
					if (i == j)
					{
						if (g[i][j] < ans)
						{       ans=g[i][j];
							anspos = i;
						}
					}
				}
			}
		}
		//cout<<anspos<<endl;
		if (anspos == -1)
		{
			return 0 * printf("SHIP IT\n");
		}
		//cout<<anspos<<endl;
		memset(used, false, sizeof(used));
		for (int j = anspos; !used[j]; j = prevv[anspos][j])
		{
			used[j] = true;
			vec.push_back(j);
		}
		for (int j = vec.size() - 1; j >= 0; j--)
			cout << mp1[vec[j]] << " ";
		cout << endl;
		return 0;
	}

J题真签到题目。

*#include<bits/stdc++.h>
using namespace std;
int main()
{
	int l,r;
	scanf("%d %d",&l,&r);
	if(l==0&&r==0)return 0*printf("Not a moose\n");
	if(r==l)return 0*printf("Even %d\n",r*2);
	else 
	{
		printf("Odd %d\n",max(l,r)*2);
	}
 } 

K题。
二分加贪心,似乎是水题。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
using namespace std;
#define ll long long
const int maxn=1e5+10;
int arr[3],brr[3],en[maxn],cnt,sum;
struct node
{
	int p1,p2,num;
}crr[15];
int cmp(node a,node b)
{
	return a.num<b.num;
}
bool solve(ll x)
{   int drr[3];
    for(int i=0;i<3;i++)drr[i]=arr[i];
	for(int i=0;i<sum;i++){
	//	double res=1.0*x/en[i];
		bool ok=true;
		for(int j=0;j<9;j++)
		{
			if(crr[j].num*en[i]>=x&&drr[crr[j].p1]!=0)
			{  
			    if(crr[j].p1==crr[j].p2&&drr[crr[j].p1]<2)continue;
			    if(drr[crr[j].p2]==0)continue;
				drr[crr[j].p1]--;
				drr[crr[j].p2]--;
				ok=false;
				break;
			}
		}
		if(ok)return false;
	}
	return true;
}
int main()
{
    while(~scanf("%d %d %d",&arr[0],&arr[1],&arr[2]))
    {
    sum=arr[0]+arr[1]+arr[2];
	for(int i=0;i<3;i++)scanf("%d",&brr[i]);
	sum/=2;
    for(int i=0;i<sum;i++)scanf("%d",&en[i]);
    for(int i=0;i<3;i++)
    for(int j=0;j<3;j++)
    {
    	crr[cnt].p1=i;
    	crr[cnt].p2=j;
    	crr[cnt].num=brr[i]+brr[j];
    	cnt++;
	}
	sort(crr,crr+cnt,cmp); 
    int l=0,r=500000000,ans=(l+r)/2;
    while(l<=r)
    {
    	int mid=(l+r)/2;
    	if(solve(mid))l=mid+1,ans=mid;
    	else r=mid-1;
	}
	cout<<ans<<endl;
}
	return 0;
}

似乎E题也不难有时间补一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值