2020牛客多校第二场

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;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值