为了那个秘密,我要努力好不好~~
A题:
/* *题目大意: * 给一个由正小六边形组成的大六边形,其六条边为a, b, c, a, b, c对称的。 * 输入a, b, c,求正小六边形的个数。 *解题思路: * 要有拆分的思想,把恶心的东西拆成人类可以理解的简单东东。算a*b + a*c + b * c * 最后发现原来中间3条长度为a, b, c的线重叠了一次,而他们又把一个点重叠了1次, * 所以公式如下。 */
View Code
#include <iostream> #include <cmath> using namespace std; int main(void) { int a, b, c; while(scanf("%d %d %d", &a, &b, &c) == 3) { printf("%d\n", a * b + a * c + b * c - a - b - c + 1); } return 0; }
B题:
/* *题目大意: * 有n个人,要平均分成两队人数相同的。然后n个人之间有仇恨, * 要求分成的两队里面都没有相互仇恨的人。最后不能分的人去 * 坐板凳,求做板凳的人数。 *解题思路: * 一开始觉得这个图很复杂,但是画了画发现原来这个图很简单, * 它分为多个连通分量,连通分量要么是链,要么是一个环。 * 如果是奇环就必须减一人,还有算所有奇链的个数模2即可。 * 判断连通分量我用了并查集。 */
View Code
#include <iostream> using namespace std; const int MAXN = 105; typedef struct _node { int p, sum; _node(): sum(1) {} }N; N uqSet[MAXN]; int findSet(int x) { if(x != uqSet[x].p) uqSet[x].p = findSet(uqSet[x].p); return uqSet[x].p; } void Union(int x, int y) { int a = findSet(x); int b = findSet(y); if(a == b) return ; else { uqSet[b].p = a; uqSet[a].sum += uqSet[b].sum; } } void init() { for(int i = 0; i < MAXN; i++) { uqSet[i].p = i; uqSet[i].sum = 1; } } int main(void) { int n, m; while(scanf("%d %d", &n, &m) == 2) { init(); int u, v, du[MAXN] = {0}, vst[MAXN] = {0}; for(int i = 0; i < m; i++) { scanf("%d %d", &u, &v); Union(u, v); du[u]++, du[v]++; } int remain = 0, sum = 0; for(int i = 1; i <= n; i++) { int f = findSet(i); if(vst[f] == 0 && du[i] != 2) { vst[f] = 1; if(uqSet[f].sum & 1) remain++; } } int must = 0; for(int i = 1; i <= n; i++) { int f = findSet(i); if(vst[f] == 0) { vst[f] = 1; if(uqSet[f].sum & 1) must++; } } printf("%d\n", must + (remain % 2)); } return 0; }
C题:
/* *题目大意: * 一个老板要雇x个人,然后x个人从雇的第一天起,要连续做n天,然后 * 放m天,这样循环,还有店里规定每天必须至少有k人,还有要交接钥匙 * 所以要注意交接必须至少有一人。 *解题思路: * 发现其实这是一个循环,只需要取其中的n+m来模拟即可。简单贪心就过了。 * 表示没有把问题抽象好。 */
View Code
#include <iostream> #include <cmath> #include <vector> using namespace std; const int MAXN = 2005; int main(void) { #ifndef ONLINE_JUDGE //freopen("in.txt", "r", stdin); #endif int n, m, k; while(scanf("%d %d %d", &n, &m, &k) == 3) { vector<int> vec; int day[MAXN] = {0}; for(int i = 0; i < k; i++) { vec.push_back(1); for(int j = 1; j <= n; j++) day[j]++; } int e = n + m; for(int i = 1; i <= e; i++) { if(day[i + 1] == 0) { vec.push_back(i); for(int j = i; j < i + n && j <= e + 1; j++) day[j]++; } while(day[i] < k) { vec.push_back(i); for(int j = i; j < i + n && j <= e + 1;j++) day[j]++; } } printf("%d\n%d", vec.size(), vec[0]); for(unsigned i = 1; i < vec.size(); i++) printf(" %d", vec[i]); printf("\n"); } return 0; }
D题:
/* *题目大意: * 题意很复杂,但是抽象起来很简单,就是有n组从小到大的序列(要自己排序)。 * 然后求任一序列的前一个序列跟后一个序列中夹在当前序列的两个数字之间的 * 数的个数是否相等,求不相等的个数。(赶时间,所以表达得真心不好,略过)。 *解题思路: * 把问题抽象了之后在纸上画了一下,发现如果暴力的话,TLE,不过既然免不了排序 * 这个环节,那么可以用二分的方法求两个数字之间夹着的数的个数,通过下标计算即可。 * 不过复杂度还是很高,主要是排序的复杂度,有1000组数据,然后快排是n*log(n), n为 * 100000,相当高。不过CF上的数据是一组一组的,这样都吃得消~~~~汗。 *解题感想: * 我把问题复杂化了~~~ */
View Code
#include <iostream> #include <algorithm> #include <vector> #include <functional> using namespace std; const int MAXN = 1005; int main(void) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif int n; while(scanf("%d", &n) == 1) { vector<int> vec[MAXN]; for(int i = 0; i < n; i++) { int k, m; scanf("%d", &k); for(int j = 0; j < k; j++) { scanf("%d", &m); vec[i].push_back(m); } sort(vec[i].begin(), vec[i].end()); } int ans = 0; for(int i = 0; i < n; i++) { int p = i - 1 < 0 ? n-1 : i - 1; int l = i + 1 > n-1? 0 : i + 1; for(int j = 0; j < vec[i].size() - 1; j++) { int up = lower_bound(vec[p].begin(), vec[p].end(), vec[i][j + 1]) - lower_bound(vec[p].begin(), vec[p].end(), vec[i][j]); int down = lower_bound(vec[l].begin(), vec[l].end(), vec[i][j + 1]) - lower_bound(vec[l].begin(), vec[l].end(), vec[i][j]); if(up != down) ans++; } } printf("%d\n", ans); } return 0; }