2020牛客暑期多校训练营(第二场)(BCDF题解)

2020牛客暑期多校训练营(第二场)(BCDF题解)_第1张图片
题目大意:
给你两个时间,要你求他们差了多少秒。
思路:
python的datetime搞搞就好了。
代码:

import datetime
if __name__ == "__main__":
    d1 = input()
    d2 = input()
    d1 = datetime.datetime.strptime(d1, "%H:%M:%S")
    d2 = datetime.datetime.strptime(d2, "%H:%M:%S")
    if(d1 > d2):
        seconds = (d1 - d2).seconds
    else :
        seconds = (d2 - d1).seconds
    print(seconds)

2020牛客暑期多校训练营(第二场)(BCDF题解)_第2张图片
2020牛客暑期多校训练营(第二场)(BCDF题解)_第3张图片
题目大意:
给你一个 n ∗ m n*m nm的矩阵,其中 a i j = l c m ( i , j ) aij=lcm(i,j) aij=lcm(i,j),现在给你一个 k k k要你求所有 k ∗ k k*k kk子矩阵的最大值之和。
思路:
这题对时间和空间卡得非常紧,构造矩阵的时候因为是对称矩阵只要求一半就行了,如果全部求出来就会超时,矩阵的类型开 i n t int int,不然超空间。
然后这题就是一个二维平面区间最大值问题了,可以用二维线段树,但是会超空间,所以这里我用的是单调队列维护二维平面最大值,最后求一下和就好了。
代码:

#include
#include
#include
#include
#include
#include
using namespace std;
 
typedef long long ll;
int ans[5001][5001];
int a[5001][5001];
deque<int> win;
int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}
void solve1(int n, int len, int* arr, int* ans) {
    win.clear();
    for (int i = 0; i < n; i++) {
        while (!win.empty() && arr[win.back()] < arr[i])
            win.pop_back();
        while (!win.empty() && win.front() < i - len + 1)
            win.pop_front();
        win.push_back(i);
        if (i + 1 >= len)
            ans[i - len + 1] = arr[win.front()];
    }
}
void solved() {
    int n, m, k; scanf("%d%d%d",&m,&n,&k);
    for (int i = 0; i < 5000; i++)
        for (int j = 0; j <= i; j++){
            a[i][j] = (i + 1) / gcd(i + 1, j + 1) * (j + 1);
            a[j][i] = a[i][j];
        }
    for (int i = 0; i < m; i++)
        solve1(n, k, a[i], ans[i]);
    int len = k;
    for (int i = 0; i < n; i++) {
        win.clear();
        for (int j = 0; j < m; j++) {
            while (!win.empty() && ans[win.back()][i] < ans[j][i])
                win.pop_back();
            while (!win.empty() && win.front() < j - len + 1)
                win.pop_front();
            win.push_back(j);
            if (j + 1 >= len)
                ans[j - len + 1][i] = ans[win.front()][i];
        }
    }
    ll res = 0;
    for (int i = 0; i < m - k + 1; i++)
        for (int j = 0; j < n - k + 1; j++)
            res += ans[i][j];
    printf("%lld\n",res);
}
int main() {
    solved();
    return 0;
}

2020牛客暑期多校训练营(第二场)(BCDF题解)_第4张图片
2020牛客暑期多校训练营(第二场)(BCDF题解)_第5张图片
题目大意:给你一颗无根树,要你找最少的链使得每条边至少被走过一次。
思路:
这题场上没写出来真是智商欠费了,这充其量是一道思维题,我们可以从一个叶子节点出发,当我们不到另外一个叶子节点停下来的时候,我们基本可以走完所有边(除了其他叶子节点的边),所以最少数量不会超过 n / 2 n/2 n/2向上取整,其中 n n n是叶子节点个数。然后我们再构造一种走法使得所有的叶子节点至少被走过一次就行了,这里采用标程的方法 l ( 1 ) − > l ( n / 2 + 1 ) , l ( 2 ) − > l ( n / 2 + 2 ) . . . . . l(1)->l(n/2+1),l(2)->l(n/2+2)..... l(1)>l(n/2+1),l(2)>l(n/2+2).....
求叶子节点顺序是用的 d f s dfs dfs序。
代码:

#include
#include
#include
#include
#include
#include
#include
using namespace std;

typedef long long int ll;
const int maxn = 2e5 + 10;
int de[maxn];
vector<int>G[maxn];
int cnt;
int dfn[maxn];
void dfs(int u,int fu){
    if(de[u] == 1){
        dfn[cnt++] = u;
        //return ;
    }
    for(int i = 0; i < G[u].size(); i++){
        int v = G[u][i];
        if(fu != v){
            dfs(v,u);
        }
    }
}
int main(){
    int n;cin>>n;
    for(int i = 1; i <= n - 1; i++){
        int u,v;cin>>u>>v;
        u--;v--;
        de[u]++;de[v]++;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(0,-1);
    int ans = (cnt + 1) / 2;
    cout<<ans<<endl;
    //for(int i = 1; i <= cnt; i++)cout<
    for(int i = 0; i < ans; i++){
        cout<<dfn[i] + 1<<" "<<dfn[(cnt/2+i)%cnt] + 1<<endl;
    }
    return 0;
}

2020牛客暑期多校训练营(第二场)(BCDF题解)_第6张图片
2020牛客暑期多校训练营(第二场)(BCDF题解)_第7张图片
题目大意:
在二维平面上给你 n n n个坐标,要你确定一个圆,使得这些点经过这个圆尽可能多。
思路:
三点确定一个圆,枚举两个点与圆点 ( 0 , 0 ) (0,0) (0,0)确定一个圆,求出圆心的坐标并且保存起来,然后统计圆心出现的次数,次数最多的是答案 a n s ans ans,不过还要求一下组合数,我们设答案为 x x x,因为我们从 x x x点取两个求的圆心,所以是 C ( x , 2 ) = x ∗ ( x − 1 ) = a n s ∗ 2 C(x,2)=x*(x-1)=ans*2 C(x,2)=x(x1)=ans2。最后枚举一下答案就行了,找到满足这个条件的。
这题会卡 m a p map map,只能自己排序然后统计个数。
代码:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 3000;
struct Point{
    double x,y;
    Point(){}
    Point(double a,double b):x(a),y(b){}
}a[maxn];
double X,Y,R;
void solve(Point a, Point b, Point c) {//三点共圆圆心公式
    if (2 * (a.y - c.y) * (a.x - b.x) - 2 * (a.y - b.y) * (a.x - c.x) == 0 && 2 * (a.y - b.y) * (a.x - c.x) - 2 * (a.y - c.y) * (a.x - b.x) == 0){X = Y = 1e18;return;}
    X = ((a.x * a.x - b.x * b.x + a.y * a.y - b.y * b.y) * (a.y - c.y) - (a.x * a.x - c.x * c.x + a.y * a.y - c.y * c.y) * (a.y - b.y)) / (2 * (a.y - c.y) * (a.x - b.x) - 2 * (a.y - b.y) * (a.x - c.x));
    Y = ((a.x * a.x - b.x * b.x + a.y * a.y - b.y * b.y) * (a.x - c.x) - (a.x * a.x - c.x * c.x + a.y * a.y - c.y * c.y) * (a.x - b.x)) / (2 * (a.y - b.y) * (a.x - c.x) - 2 * (a.y - c.y) * (a.x - b.x));
    R = sqrt((X - a.x) * (X - a.x) + (Y - a.y) * (Y - a.y));
}
bool cmp(pair<double,double> a,pair<double,double> b){
    if(a.first != b.first)return a.first < b.first;
    else return a.second < b.second;
}
int main(){
    int n;cin>>n;
    for(int i = 1; i <= n; i++){
        scanf("%lf%lf",&a[i].x,&a[i].y);
    }
    if(n == 1){
        cout<<"1"<<endl;return 0;
    }
    vector<pair<double,double> >ve;
    for(int i = 1; i <= n; i++){
        for(int j = i + 1; j <= n; j++){
            solve(Point{0,0},a[i],a[j]);
            if(X == Y && fabs(X - 1e18) < 1e-8)continue;
            ve.push_back(make_pair(X,Y));
        }
    }
    if(ve.size() == 0){
        cout<<"1"<<endl;return 0;
    }
    int _max = 0;
    sort(ve.begin(),ve.end(),cmp);
    pair<double,double>cur = ve[0];
    int cnt = 1;
    for(int i = 1; i < ve.size(); i++){
        if(ve[i] == cur)++cnt;
        else {
            cur = ve[i];
            cnt = 1;
        }
        _max = max(_max,cnt);
    }
    for(int i = 1; i <= n; i++){
        if(i * (i - 1) == _max * 2){
            printf("%d\n",i);
            return 0;
        }
    }
    return 0;
}

你可能感兴趣的:(思维题)