A. Eating Soup
题意
给定n个人围成一圈,在离开m个人后,问最多能分成多少个不连通的部分。
关键词
构造
思路
分成几种情况进行考虑:
-
:
人全走了,结果为。
-
或
:
最多走了一个人,所有人还是连在一起,结果为。
-
:
走了超过一半的人,剩下的人,每个人都可以单独坐,结果为。
-
:
超过一半的人剩下,可以假设走的个人不相连,则最多分成
个不相连的部分,结果为
。
代码
//#include <bits/stdc++.h> #include <algorithm> #include <cstdio> #include <iostream> #include <vector> #include <cstring> #include <string> #include <climits> #include <cmath> #include <stack> #include <functional> #define Debug 0 #define MAXN 115 #define MAXM 200 #define MAXK 10000010 #define MOD 1000000007 #define INF 0x3f3f3f3f #define PI 3.1415926535 #define pb push_back #define SYNC ios::sync_with_stdio(false); #define MSET(arr, v) memset((arr),(v),sizeof(arr)) #define SCAND(n) scanf("%d", &n) #define PRINTD(n) printf("%d", n) #define EPS 1e-6 #define null Point(EPS/10, EPS/10) //#define FILE_IN "I:\\acm-workspace\\CLion-Project\\in.txt" typedef long long ll; typedef std::pair<int, int> Pair; using namespace std; int main () { #ifdef FILE_IN freopen(FILE_IN, "r", stdin); #endif // SYNC int n, m; cin >> n >> m; int t = n / 2; int ans = 0; if (m == n) ans = 0; else if (m == 0 || m == 1) ans = 1; else if (m > t) ans = n - m; else ans = m; cout << ans << endl; #ifdef FILE_IN fclose(stdin); #endif return 0; }
B. Cat Party (Hard Edition)
题意
给定n个颜色,问从第一个颜色开始,能够满足在去除其中一个颜色后,剩余每种颜色数量全部相同的最长颜色序列长度为多少。
关键词
构造、贪心
思路
对于一个长度为 颜色序列,可以分为四种情况:
- 恰好有
个不同的颜色。
- 恰好
个颜色都为同一种颜色。
- 恰好有
种颜色数量为
,其他颜色数量相同。
- 其他颜色数量相同,恰好有
种颜色数量比其他颜色多
个。
显然,每当从 开始的长度为
的序列满足以上四种情况之一时,可以用长度
更新结果,取最大值。
代码
#include <bits/stdc++.h> #define Debug 0 #define MAXN 100006 #define MAXM 100006 #define MAXK 10000010 #define MOD 1000000007 #define INF 0x3f3f3f3f #define PI 3.1415926535 #define pb push_back #define SYNC ios::sync_with_stdio(false); #define MSET(arr, v) memset((arr),(v),sizeof(arr)) #define SCAND(n) scanf("%d", &n) #define PRINTD(n) printf("%d", n) #define EPS 1e-6 #define null Point(EPS/10, EPS/10) //#define FILE_IN "I:\\acm-workspace\\CLion-Project\\in.txt" typedef long long ll; typedef std::pair<int, int> Pair; using namespace std; int arr[MAXN]; int cnt[MAXN] = {0}; // cnt[i]: 有多少种颜色出现了i次 int color[MAXN] = {0}; // color[i]: 第i种颜色出现的次数 int n; int main () { #ifdef FILE_IN freopen(FILE_IN, "r", stdin); #endif // SYNC cin >> n; set<int> se; int ans = 1; for (int i = 0; i < n; ++i) { cin >> arr[i]; se.insert(arr[i]); } if (se.size() == 1 || se.size() == n) { ans = n; } else { int ma = 0; for (int i = 0; i < n; ++i) { int c = arr[i]; cnt[color[c]]--; color[c]++; cnt[color[c]]++; ma = max(ma, color[c]); if (cnt[1] == 1 && ma * cnt[ma] == i) ans = i + 1; else if (cnt[ma] == 1 && (ma-1) * cnt[ma-1] + ma == i + 1) ans = i + 1; } } cout << ans << endl; #ifdef FILE_IN fclose(stdin); #endif return 0; }
C. Power Transmission (Hard Edition)
题意
给定个点,并且任意两点连一条直线,问有多少对直线相交。
当三点共线时,其所在直线为同一条直线。
关键词
计算几何、暴力
思路
计算任意两点的连线,并排除共线的情况,在余下的直线中,排除平行的情况,其他直线都相交。
设给定两个点 所连成的直线为
,这里用直线的一般公式
来表示一条直线会更方便。
对于系数 、
和常数
,有:
对 和
约分化简,并保证符号相同,在该前提下:
- 可以通过
、
来唯一表示一条直线的斜率
。
- 对于相同的斜率
,可以通过常数
来区分平行的不同直线。
- 当
和
相同且
也相同时,则可以判定2条直线相同(共线)。
显然,可以按照斜率 将直线分组,对于每条直线,与其相交的直线数则为:(总直线数量-斜率为k的直线数量)。
对每条直线累加该值即为结果。
代码
#include <bits/stdc++.h> #define Debug 0 #define MAXN 115 #define MAXM 100006 #define MAXK 10000010 #define MOD 1000000007 #define INF 0x3f3f3f3f #define PI 3.1415926535 #define pb push_back #define SYNC ios::sync_with_stdio(false); #define MSET(arr, v) memset((arr),(v),sizeof(arr)) #define SCAND(n) scanf("%d", &n) #define PRINTD(n) printf("%d", n) #define EPS 1e-8 #define null Point(EPS/10, EPS/10) //#define FILE_IN "I:\\acm-workspace\\CLion-Project\\in.txt" typedef long long ll; typedef std::pair<int, int> Pair; using namespace std; // 二维向量 struct Vector { double x, y; Vector () {} Vector (double x, double y) : x(x), y(y) {} // 点积 double operator* (Vector v) { return x * v.x + y * v.y; } // 叉积 double operator^ (Vector v) { return x * v.y - y * v.x; } // 乘法 Vector operator* (double d) { return Vector(x * d, y * d); } // 加法 Vector operator+ (Vector v) { return Vector(x + v.x, y + v.y); } // 减法 Vector operator- (Vector v) { return Vector(x - v.x, y - v.y); } bool operator== (const Vector &rhs) const { return x == rhs.x && y == rhs.y; } bool operator!= (const Vector &rhs) const { return !(rhs == *this); } // 模 double length () { return sqrt((*this) * (*this)); } // 单位化 Vector unit () { return (*this) * (1.0 / length()); } // 逆时针旋转alpha角(弧度) Vector rotate (double alpha) { return Vector(x + (x * cos(alpha) - y * sin(alpha)), y + (x * sin(alpha) + y * cos(alpha))); } // v的投影 double project (Vector v) { return v * unit(); } bool operator< (Vector v) const { if (x != v.x) return x < v.x; else return y < v.y; } bool operator> (Vector v) const { if (x != v.x) return x > v.x; else return y > v.y; } }; typedef Vector Point; // 二维直线 struct Line { Point x, y; // 通过两点构造直线 Line (Point x, Point y) : x(x), y(y) {} Line () {} // 点和方向向量来构造线 static Line makeLine (Point x, Vector v) { return Line(x, x + v); } bool operator== (const Line &rhs) const { return x == rhs.x && y == rhs.y; } bool operator!= (const Line &rhs) const { return !(rhs == *this); } // 线长度 double length () { return (y - x).length(); } // 点到该直线的距离 double dist (Point p) { return fabs((x - p) ^ (y - p)) / length(); } // #define EPS 1e-6 // 判断点和直线的位置 int side (Point p) { double result = (y - x) ^(p - x); if (fabs(result) < EPS) return 0; // 在线上 else if (result > 0) return 1; // 左侧 else return -1; // 右侧 } // 过点做垂线 Line vertical (Point p) { return makeLine(p, (y - x).rotate(PI / 2)); } // 垂足 Point foot (Point p) { Vector self = y - x; return x + self.unit() * self.project(p - x); } pair<int, Point> intersect (Line l) { double s1 = ((x - l.x) ^ (l.y - l.x)) / 2; double s2 = ((l.y - l.x) ^ (y - l.x)) / 2; if (fabs(s1 + s2) < EPS) { if (l.dist(x) < EPS) return make_pair(1, l.x); // 重合 else return make_pair(2, l.y); // 平行 } else return make_pair(0, x + (y - x) * (s1 / (s1 + s2))); // 交点 } }; int n; int main () { #ifdef FILE_IN freopen(FILE_IN, "r", stdin); #endif SYNC cin >> n; vector<Point> pt; vector<Line> ls; map<Pair, set<ll>> ma; for (int i = 0; i < n; ++i) { int a, b; cin >> a >> b; pt.pb(Point(a, b)); } ll tot = 0; ll ans = 0; for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { int a = pt[i].y - pt[j].y; int b = pt[i].x - pt[j].x; int d = __gcd(a, b); a /= d; b /= d; if (a < 0 || (a == 0 && b < 0)) { a *= -1; b *= -1; } ll c = 1LL * pt[i].x * a - 1LL * pt[i].y * b; Pair pr(a, b); if (ma[pr].count(c) == 0) { tot++; ma[pr].insert(c); ans += tot - ma[pr].size(); } } } cout << ans << endl; #ifdef FILE_IN fclose(stdin); #endif return 0; }