2015年浙江省赛总结

这是我们队伍自己组织打的第一场组队赛。但是由于经验不足加上没有提前休息好,这次打的并不是太好,只做了5题。。。比赛结束之后回去补题,发现那5题真的是秒杀,一个小时就可以全部搞定。然而我们却花了快2个小时。最后3小时一直没有出题。


本次的浙江省赛题目质量还是可以的,基础题占了大部分,很能考验代码的基本功。下面补上我做出来的8道题的题解。

A - Ace of Aces

1.题目描述:点击打开链接

2.解题思路:一道普通的计数题,标记每个人出现的次数cnt和每个cnt出现的次数,如果最大的cnt出现超过2次就输出Nobody,否则输出最大的cnt对应的那个人。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<long long, long long> PL;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)


#define N 1000+5
int vis[N];
int cur[N];

int main()
{
	//freopen("t.txt", "r", stdin);
	int T;
	cin >> T;
	while (T--)
	{
		me(vis); me(cur);
		int n;
		scanf("%d", &n);
		while (n--)
		{
			int x;
			cin >> x;
			vis[x]++;
			cur[vis[x]]++;
		}
		int i;
		for (i = 1; cur[i]; i++);
		i--;
		if (cur[i] == 1){
			for (int j = 1; j <= 1000;j++)
			if (vis[j] == i){
				printf("%d\n", j);
				break;
			}
		}
		else puts("Nobody");
	}
	return 0;
}


B - Team Formation

1.题目描述:点击打开链接

2.解题思路:本题利用加法原理解决。这道题在比赛时没有做出来,不过在比赛时候想到了会跟一个数的反码有关。最后发现就是这样做的。首先按照二进制表示法中最高位1的位置来分类,分别统计每一类有几个数。由题目知,只需要32位即可。将统计的结果放入bit数组中。接下来,根据条件A^B>max{A,B},从二进制的角度考虑,就是A的二进制法表示中,某些为0的地方在B的表达式中却是1,这样异或值才会增大。这就告诉我们,只需要枚举每个元素即可,对于每个元素,先找到二进制表示法中最高位1的位置是b。那么所有符合的结果sum{bit[i]|i<b且a的第i位是0}。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<long long, long long> PL;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)

#define N 1000010
int a[N];
int bit[32];

int main()
{
	//freopen("t.txt", "r", stdin);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n;
		scanf("%d", &n);
		me(bit);
		For(i, n)
		{
			scanf("%d", &a[i]);
			int l = 31;
			while (l>=0)
			if (a[i] & (1 << l)){
				bit[l]++; break;//找a[i]的最高位
			}
			else l--;
		}
		sort(a, a + n);
		ll ans = 0;
		For(i, n)//枚举每一个元素
		{
			int b = 31;
			while (b >= 0)//找二进制表示法中1的最高位
			{
				if (a[i] & (1 << b))break;
				b--;
			}
			while (b >= 0)//统计个数
			{
				if (!(a[i] & (1 << b)))ans += bit[b];
				b--;
			}
		}
		printf("%lld\n", ans);
	}
	return 0;
}


D - Beauty of Array

1.题目描述:点击打开链接

2.解题思路:本题是一个很经典的计数问题。要求出所有连续子集中不同元素的和。我们可以尝试从递推的角度考虑:假设已经计算好了前i-1个元素的和,那么增加一个元素a[i]会发生什么变化呢?假设前一次a[i]出现在位置pre[a[i]],那么新加入的a[i]所产生的新的和就是pre[a[i]]+1到当前的这个范围的和,增加的和值为(i-pre[a[i]])*a[i]。那么以i结尾的部分的和即为sum[i]=sum[i-1]+(i-pre[a[i]])*a[i]。那么最终的答案就是所有的sum[i]之和。不过这里的sum[i]数组还可以只用一个变量sum来代替。只需要每次输入新的元素时及时更新sum的值,最后在累加上ans即可。有点类似于滚动数组。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<long long, long long> PL;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)

#define N 100000+5
int pre[N];
int n;

int main()
{
	//freopen("t.txt", "r", stdin);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d", &n);
		me(pre);
		ll ans = 0, sum = 0, x;
		for (int i = 1; i <= n; i++)
		{
			scanf("%lld", &x);
			sum += (i - pre[x])*x;//更新sum
			ans += sum;//最后更新ans
			pre[x] = i;
		}
		printf("%lld\n", ans);
	}
	return 0;
}



G - Lunch Time

1.题目描述: 点击打开链接
2.解题思路:本题是一道简单的模拟题,先找到中位数,然后累加ans即可。这里有一个技巧,对于n的奇偶性不需要分别讨论,都是n/2即可(手算即可验证该结论)。
3.代码:
#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<long long, long long> PL;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)

#define N 105
struct Node
{
	char name[60];
	int price;
	bool operator<(const Node rhs)const
	{
		return price < rhs.price;
	}
	void read()
	{
		scanf("%s%d", name, &price);
	}
}a[N],b[N],c[N];

int s, m, d;
int main()
{
	//freopen("t.txt", "r", stdin);
	int T;
	cin >> T;
	while (T--)
	{
		scanf("%d%d%d", &s, &m, &d);
		me(a); me(b); me(c);
		For(i, s)a[i].read();
		For(i, m)b[i].read();
		For(i, d)c[i].read();
		sort(a, a + s);
		sort(b, b + m);
		sort(c, c + d);
		int sum = 0;
		For(i, 3)
		{
			if (i == 0)sum += a[s / 2].price;
			else if (i == 1)sum += b[m / 2].price;
			else sum+=c[d / 2].price;
		}
		printf("%d %s %s %s\n", sum, a[s / 2].name, b[m / 2].name, c[d / 2].name);
	}
	return 0;
}

H - May Day Holiday

1.题目描述: 点击打开链接
2.解题思路:本题也是一道简单题,只需要事先标记出所有的闰年,然后从1928年开始计算每一年的5.1日是星期几即可。事先也要对从周日到周六开始的五一节日的长度进行打表。
3.代码:
#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<long long, long long> PL;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)

#define N 10005
int vis[N];
int a[N];
const int d[] = { 6, 9, 6, 5, 5, 5, 5 };
void init()
{
	me(vis); me(a);
	for (int i = 1928; i <= 9999;i++)
	if ((i % 4 == 0 && i % 100 != 0) || i % 400 == 0)
		vis[i] = 1;
	a[1928] = 2;
	for (int i = 1929; i <= 9999; i++)
	{
		int d = vis[i] ? 2 : 1;
		a[i] = (a[i - 1] + d) % 7;
	}
}
int main()
{
	//freopen("t.txt", "r", stdin);
	int T;
	init();
	cin >> T;
	while (T--)
	{
		int n;
		scanf("%d", &n);
		printf("%d\n", d[a[n]]);
	}
	return 0;
}

J - Convert QWERTY to Dvorak

1.题目描述: 点击打开链接
2.解题思路:本题是一道字符串处理题目,事先对没有按Shift键的所有字母打表,然后再对按了Shift键的字母打表。输入一个串后扫描每一个字符,看它属于哪一种情况,直接转换后输出即可。
3.代码:
#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<long long, long long> PL;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)

const char*s1 = "`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./";
const char*s2 = "~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?";

const char*t1 = "`1234567890[]',.pyfgcrl/=\\aoeuidhtns-;qjkxbmwvz";
const char*t2 = "~!@#$%^&*(){}\"<>PYFGCRL?+|AOEUIDHTNS_:QJKXBMWVZ";

int id1(char c){ return strchr(s1, c) - s1; }
int id2(char c){ return strchr(s2, c) - s2; }

int main()
{
	//freopen("t.txt", "r", stdin);
	string s;
	int L = strlen(s1);
	while (getline(cin, s))
	{
		int len = s.size();
		For(i, len)
		{
			int k1 = id1(s[i]);
			int k2 = id2(s[i]);
			if (k1 >= 0 && k1 < L)
				putchar(t1[k1]);
			else if (isspace(s[i]))putchar(s[i]);
			else putchar(t2[k2]);
		}
		printf("\n");
	}
	return 0;
}

K - Capture the Flag

1.题目描述: 点击打开链接
2.解题思路:本题是一道模拟题,然而好久没有练习这种题型了,比赛时候还是没能做出来,比赛后补题也是费了很大功夫才通过的。看来模拟题要不定期的经常训练才可以==。本题虽然题意很长,但读懂后思路还是非常清晰的,一共分4个过程,攻击,保持,获得名次,查询;因此分别写四个函数来处理这四个阶段即可:Attack(),Maintain(),getRank(),Query()。
不过这里要注意:由于分数是浮点数,因此不能直接通过大于,小于就能找到名次,必须专们写一个dcmp比较函数,当差的绝对值小于eps时应该视为相等,否则再分大于,小于两种情况。
3.代码:
#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<long long, long long> PL;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)

#define N 105

struct Node
{
	double score;
	int rnk;
}a[N];

struct Tmp
{
	double s;
	int id;
	bool operator<(const Tmp&A)const
	{
		return s>A.s;
	}
}tmp[N];
int n, q, s, c;
const double eps = 1e-5;
int server[N];
int vis[N][N][11];

int dcmp(double a, double b)//一定要通过该函数来判断大小
{
	if (fabs(a - b) < eps)return 0;
	else if (a>b)return 1;
	else return -1;
}
void Attack()
{
	int attack;
	me(vis);
	scanf("%d", &attack);
	For(i, attack)
	{
		int u, v, r;
		scanf("%d%d%d", &u, &v, &r);
		u--, v--, r--;
		if (!vis[u][v][r])
			vis[u][v][r] = 1;
	}
	for (int i = 0; i < q;i++)
	for (int j = 0; j < n; j++)
	{
		int cnt = 0;
		for (int k = 0; k < n;k++)
		if (vis[k][j][i])cnt++;
		if (!cnt)continue;
		a[j].score -= (double)(n - 1);
		for (int k = 0; k < n;k++)
		if (vis[k][j][i])
			a[k].score += (double)(n - 1) / (double)cnt;
	}
}
void Maintain()
{
	me(server);
	For(i, q)
	{
		int success = 0;
		For(j, n)
		{
			scanf("%d", &server[j]);
			if (server[j])success++;
		}
		int fail = n - success;
		For(j, n)
		if (server[j])a[j].score += (double)(n - 1)*fail / (double)success;
		else a[j].score -= (double)(n - 1);
	}
}
void getRank()
{
	for (int i = 0; i < n; i++)
	{
		tmp[i].s = a[i].score;
		tmp[i].id = i;
	}
	sort(tmp, tmp + n);
	int idx = 1;
	a[tmp[0].id].rnk = 1;
	for (int i = 1; i < n; i++){
		if (dcmp(tmp[i].s, tmp[i - 1].s))idx = i+1;
		a[tmp[i].id].rnk = idx;
	}
}
void Query()
{
	int query,id;
	scanf("%d", &query);
	while (query--)
	{
		scanf("%d", &id);
		id--;
		printf("%.8lf %d\n", a[id].score, a[id].rnk);
	}
}
int main()
{
	//freopen("t.txt", "r", stdin);
	int T;
	scanf("%d", &T);
	while (T--)
	{
		me(a);
		scanf("%d%d%d%d", &n, &q, &s, &c);
		For(i, n)a[i].score = s;
		while (c--)
		{
			Attack();
			Maintain();
			getRank();
			Query();
		}
	}
	return 0;
}


L - Demacia of the Ancients

1.题目描述: 点击打开链接
2.解题思路:本题是一道简单的搜索题,找有多少个数大于6000,扫描一遍统计即可。
3.代码:
#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<long long, long long> PL;
#define me(s) memset(s,0,sizeof(s))
#define For(i,n) for(int i=0;i<(n);i++)


#define N 10+5
int a[N];

int main()
{
	//freopen("t.txt", "r", stdin);
	int T;
	cin >> T;
	while (T--)
	{
		int n;
		cin >> n;
		int cnt = 0;
		For(i, n)
		{
			scanf("%d", &a[i]);
			if (a[i] > 6000)cnt++;
		}
		printf("%d\n", cnt);
	}
	return 0;
}




你可能感兴趣的:(组队赛总结)