B 计算几何 三点定圆
- Boundary
题意:
给你n个点,现在确定一个点是原点,让你从n个点里选尽量多的点,让这些点在同一个圆上,问最多的点数是多少。
n<=2000
思路:
注意先要判三点是否共线,然后再求圆。
n=1的时候特判。
因为三个点确定一个圆,有因为已经确定了一个原点,所以可以O(n^2)遍历所有的可能,得出圆心,别忘了最后更新ans的时候是res+1,因为是固定了某个点求的,更新答案的时候要把那个固定的点加上。
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
const int N=2100;
//Compares a double to zero
int n,x[N],y[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
else return 1;
}
struct Point {
double x, y;
Point() {}
Point(double _x, double _y) {
x = _x;
y = _y;
}
bool operator == (Point b) const {
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator < (Point b) const {
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator - (const Point &b) const {
return Point(x - b.x, y - b.y);
}
//点积
double operator * (const Point &b) const {
return x * b.x + y * b.y;
}
//叉积
double operator ^ (const Point &b) const {
return x * b.y - y * b.x;
}
Point operator + (const Point &b) const {
return Point(x + b.x, y + b.y);
}
Point operator * (const double &k) const {
return Point(x * k, y * k);
}
Point operator / (const double &k) const {
return Point(x / k, y / k);
}
//逆时针旋转 90 度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转 90 度
Point rotright() {
return Point(y, -x);
}
//绕着 p 点逆时针旋转 angle
Point rotat(Point p, double angle) {
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
double distance(Point p) {
return hypot(x - p.x, y - p.y);
}
}po[N];
struct Line{
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s;
e = _e;
}
bool operator == (Line v) {
return (s == v.s) && (e == v.e);
}
Point crosspoint(Line v) {
double a1 = (v.e - v.s) ^ (s - v.s);
double a2 = (v.e - v.s) ^ (e - v.s);
return Point((s.x * a2 - e.x * a1) / (a2 - a1),
(s.y * a2 - e.y * a1) / (a2 - a1));
}
};
struct circle{
Point p; //圆心
double r; //半径
circle(Point _p, double _r){
p = _p;
r = _r;
}
circle(double x, double y, double _r){
p = Point(x, y);
r = _r;
}
//三角形的外接圆
//需要Point的 + / rotate() distance()以及 Line 的 crosspoint()
//注意:先要判三点不共线
//利用两条边的中垂线得到圆心
//测试:UVA 12304
circle(Point a, Point b, Point c){
Line u = Line((a+b)/2, ((a+b)/2) + ((b-a).rotleft()));
Line v = Line((b+c)/2, ((b+c)/2) + ((c-b).rotleft()));
p = u.crosspoint(v);
r = p.distance(a);
}
};
bool sameLine(Point a, Point b, Point c){
double ax=c.x-a.x, ay=c.y-a.y;
double bx=c.x-b.x, by=c.y-b.y;
if(sgn(ax*by-ay*bx)==0)return true;
return false;
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n;
for(int i=1; i<=n; ++i){
cin>>x[i]>>y[i];
po[i]=Point(x[i], y[i]);
}
if(n==1) {
cout<<1<<'\n';
return 0;
}
Point bp=Point(0, 0);
vector< pair<double, double> > cc;
int ans=1;
for(int i=1; i<=n; ++i){
cc.clear();
for(int j=i+1; j<=n; ++j){
if(sameLine(po[i], po[j], bp)) continue;
circle tmp=circle(bp, po[i], po[j]);
cc.emplace_back(make_pair(tmp.p.x, tmp.p.y));
}
sort(cc.begin(), cc.end());
int res=1;
for(int i=1; i<int(cc.size()); ++i){
if(fabs(cc[i].first-cc[i-1].first)<eps && fabs(cc[i].second-cc[i-1].second)<eps){
++res;
} else{
res=1;
}
ans=max(ans, res+1);
}
}
cout<<ans<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
直接用map< pair<double, double>, int>
也不会被卡,代码如下:
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;
const int N=2100;
//Compares a double to zero
int n,x[N],y[N];
int sgn(double x) {
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
else return 1;
}
struct Point {
double x, y;
Point() {}
Point(double _x, double _y) {
x = _x;
y = _y;
}
bool operator == (Point b) const {
return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
}
bool operator < (Point b) const {
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
Point operator - (const Point &b) const {
return Point(x - b.x, y - b.y);
}
//点积
double operator * (const Point &b) const {
return x * b.x + y * b.y;
}
//叉积
double operator ^ (const Point &b) const {
return x * b.y - y * b.x;
}
Point operator + (const Point &b) const {
return Point(x + b.x, y + b.y);
}
Point operator * (const double &k) const {
return Point(x * k, y * k);
}
Point operator / (const double &k) const {
return Point(x / k, y / k);
}
//逆时针旋转 90 度
Point rotleft() {
return Point(-y, x);
}
//顺时针旋转 90 度
Point rotright() {
return Point(y, -x);
}
//绕着 p 点逆时针旋转 angle
Point rotat(Point p, double angle) {
Point v = (*this) - p;
double c = cos(angle), s = sin(angle);
return Point(p.x + v.x * c - v.y * s, p.y + v.x * s + v.y * c);
}
double distance(Point p) {
return hypot(x - p.x, y - p.y);
}
}po[N];
struct Line{
Point s, e;
Line() {}
Line(Point _s, Point _e) {
s = _s;
e = _e;
}
bool operator == (Line v) {
return (s == v.s) && (e == v.e);
}
Point crosspoint(Line v) {
double a1 = (v.e - v.s) ^ (s - v.s);
double a2 = (v.e - v.s) ^ (e - v.s);
return Point((s.x * a2 - e.x * a1) / (a2 - a1),
(s.y * a2 - e.y * a1) / (a2 - a1));
}
};
struct circle{
Point p; //圆心
double r; //半径
circle(Point _p, double _r){
p = _p;
r = _r;
}
circle(double x, double y, double _r){
p = Point(x, y);
r = _r;
}
//三角形的外接圆
//需要Point的 + / rotate() distance()以及 Line 的 crosspoint()
//注意:先要判三点不共线
//利用两条边的中垂线得到圆心
//测试:UVA 12304
circle(Point a, Point b, Point c){
Line u = Line((a+b)/2, ((a+b)/2) + ((b-a).rotleft()));
Line v = Line((b+c)/2, ((b+c)/2) + ((c-b).rotleft()));
p = u.crosspoint(v);
r = p.distance(a);
}
};
bool sameLine(Point a, Point b, Point c){
double ax=c.x-a.x, ay=c.y-a.y;
double bx=c.x-b.x, by=c.y-b.y;
if(sgn(ax*by-ay*bx)==0)return true;
return false;
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n;
for(int i=1; i<=n; ++i){
cin>>x[i]>>y[i];
po[i]=Point(x[i], y[i]);
}
if(n==1) {
cout<<1<<'\n';
return 0;
}
Point bp=Point(0, 0);
map< pair<double, double>, int> mp;
int ans=1;
for(int i=1; i<=n; ++i){
mp.clear();
for(int j=i+1; j<=n; ++j){
if(sameLine(po[i], po[j], bp)) continue;
circle tmp=circle(bp, po[i], po[j]);
mp[make_pair(tmp.p.x, tmp.p.y)]++;
}
for(auto it : mp){
ans=max(ans, it.second+1);
}
}
cout<<ans<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
C 无向无环图最小链覆盖所有边
题意:
给你一个无向无环图,要用最少的链覆盖所有的边,输出数量,以及每个链的链首和链尾。
思路:
从根节点做一下dfs,得到所有的叶子结点,然后第i个和第i+(len+1)/2个叶子结点配对,如果叶子节点数量是奇数就再加上一条root到中间的叶子结点的链。
#include <bits/stdc++.h>
using namespace std;
const int N=2*(int)1e5+100;
int n,deg[N];
vector<int> G[N];
vector<int> leaf;
void dfs(int now, int pre){
if(deg[now]==1){
leaf.emplace_back(now);
}
for(int to:G[now]){
if(to==pre) continue;
dfs(to, now);
}
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n;
for(int i=0; i<n-1; ++i){
int u,v;
cin>>u>>v;
++deg[u];
++deg[v];
G[u].emplace_back(v);
G[v].emplace_back(u);
}
int root=1;
for(int i=1; i<=n; ++i){
if(deg[i]>1){
root=i;
break;
}
}
dfs(root, -1);
int len=int(leaf.size());
cout<<(len+1)/2<<'\n';
for(int i=0; i<len/2; ++i){
cout<<leaf[i]<<' '<<leaf[i+(len+1)/2]<<'\n';
}
if(len&1){
cout<<root<<' '<<leaf[len/2]<<'\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
D 签到
- Duration
题意:
给你两个用MM:HH:SS表示的时间,现在问你他们之间差了多少秒?
思路:
全都化成秒,相减,取绝对值。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a, b, c;
ll s1 = 0, s2 = 0;
char ch1, ch2;
ll myabs(ll x) {return (x < 0 ? -x : x);}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin >> a >> ch1 >> b >> ch2 >> c;
s1 = a * 3600 + b * 60 + c;
cin >> a >> ch1 >> b >> ch2 >> c;
s2 = a * 3600 + b * 60 + c;
cout << myabs(s2 - s1) << '\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
F 单调队列 线性求二维gcd
- Fake Maxpooling
题意:
有一个n*m的矩阵,(i,j)的值是lcm(i,j)现在取出所有的k*k的正方形矩阵,每个正方形矩阵里面都有一个最大元素,问所有正方形的最大元素之和是多少?
思路
先线性求二维gcd,但这题也没卡暴力。
然后问题模型就变成了维护所有k*k矩阵的最大值
了,这是单调队列的经典题型。
#include <bits/stdc++.h>
using namespace std;
const int N=5050;
int n,m,k,a[N][N],b[N][N];
deque<int> dq;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>n>>m>>k;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
for(int i=1; i<=n; ++i){
for(int j=1; j<=m; ++j){
if(!a[i][j]){
for(int k=1; k*i<=n && k*j<=m; ++k){
a[i*k][j*k]=k; b[i*k][j*k]=i*j*k;
}
}
}
}
memset(a, 0, sizeof(a));
for(int i=1; i<=n; ++i){
while(!dq.empty()) dq.pop_front();
dq.push_back(0);
for(int j=1; j<=m; ++j){
while(!dq.empty() && j-dq.front()>=k) dq.pop_front();
while(!dq.empty() && b[i][j]>=b[i][dq.back()]) dq.pop_back();
dq.push_back(j);
a[i][j]=b[i][dq.front()];
}
}
long long ans=0;
for(int j=1; j<=m; ++j){
while(!dq.empty()) dq.pop_front();
dq.push_back(0);
for(int i=1; i<=n; ++i){
while(!dq.empty() && i-dq.front()>=k) dq.pop_front();
while(!dq.empty() && a[i][j]>=a[dq.back()][j]) dq.pop_back();
dq.push_back(i);
if(i>=k && j>=k) ans+=a[dq.front()][j];
}
}
cout<<ans<<'\n';
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}