The 2019 ICPC Asia Nanjing Regional Contest(A、C、K)

A. A Hard Problem

在全排列1到n中每k个数作为一段,每段必存在u,v使得u是v的一个因子,考虑每段最短是多长,直接倒着考虑,假如n=6,最后肯定是要3...6才能符合题意,假如n=7,最后必须是3...7才能符合题意...以此类推,发现每一段必定是\left \lceil \frac{n}{2} \right \rceil+1个数,才能符合题意

AC代码:

#include <bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<n;i++)
using namespace std;
using LL = long long;

void Solve() {
    int n;
    cin >> n;
    int k = (n + 1) / 2;
    cout << k + 1 << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    rep (i, 0, T) {
        Solve();
    }

    return 0;
}

C. Digital Path

这个题他问的是1->2->3->4->...中至少走连续四步的个数,需要记录的是每个点的出度和入度,以及只有入度为0的点才可以放进队列里进行bfs,剩下的可以dp解决,考虑走到(i,j)这个点时用了k步进行转移,为了不重复的计算一条路径,可以每次到一个点就将这个点的入度-1,直到入度减为0再将它放进队列里等待下次bfs它,最后统计每个出度不为0、走四步及以上能走到它的点的方案数

AC代码:

#include <bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<n;i++)
using namespace std;
using LL = long long;

const int mod = 1e9 + 7;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;
    vector<vector<int>> in(n + 1, vector<int> (m + 1));
    vector<vector<int>> out(n + 1, vector<int> (m + 1));
    vector<vector<int>> mp(n + 1, vector<int> (m + 1));
    vector<vector<vector<int>>> dp(n + 1, vector<vector<int>> (m + 1, vector<int> (5)));
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cin >> mp[i][j];
        }
    }
    const vector<int> movx {-1, 0, 1, 0};
    const vector<int> movy {0, 1, 0, -1};
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            for (int k = 0; k < 4; k++) {
                int xx = i + movx[k], yy = j + movy[k];
                if (xx < 1 || xx > n || yy < 1 || yy > m) {
                    continue;
                }
                if (mp[i][j] == mp[xx][yy] + 1) {
                    in[i][j]++;
                }
                if (mp[i][j] == mp[xx][yy] - 1) {
                    out[i][j]++;
                }
            }
        }
    }
    queue<pair<int, int>> qu;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (!in[i][j]) {
                dp[i][j][1] = 1;
                qu.push(make_pair(i, j));
            }
        }
    }
    while (!qu.empty()) {
        int x = qu.front().first, y = qu.front().second;
        qu.pop();
        for (int i = 0; i < 4; i++) {
            int xx = x + movx[i], yy = y + movy[i];
            if (xx < 1 || xx > n || yy < 1 || yy > m) {
                continue;
            }
            if (mp[x][y] + 1 == mp[xx][yy]) {
                dp[xx][yy][2] = (dp[xx][yy][2] + dp[x][y][1]) % mod;
                dp[xx][yy][3] = (dp[xx][yy][3] + dp[x][y][2]) % mod;
                dp[xx][yy][4] = (dp[xx][yy][4] + dp[x][y][3] + dp[x][y][4]) % mod;
                if (--in[xx][yy] == 0) {
                    qu.push(make_pair(xx, yy));
                }
            }
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (!out[i][j]) {
                ans = (ans + dp[i][j][4]) % mod;
            }
        }
    }
    cout << ans << '\n';

    return 0;
}

K. Triangle

题意是给出一个三角形和一个点,判断三角形上是否存在另一个点使得两点所成线段将三角形面积一分为二,首先要判断的是给出的点是否在三角形的边上,其次可以判断给出的点在三边的哪条边上,然后判断给出的点在这条边的靠近哪个顶点处,然后可以通过画出三角形来判断要输出的点应该在哪条边上,然后二分判断线段切割的面积即可,建议使用较快的输入输出和C++版本

AC代码:

#include <bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<n;i++)
using namespace std;
using LL = long long;
const double eps = 1e-8;
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;
    }
    void input(){
        scanf("%lf%lf", &x, &y);
    }
    bool operator == (Point b)const{
        return sgn(x-b.x) == 0 && sgn(y-b.y) == 0;
    }
    Point operator -(const Point &b)const{
        return Point(x-b.x, y-b.y);
    }
    //叉积
    double operator ^(const Point &b)const{
        return x*b.y - y*b.x;
    }
    //点积
    double operator *(const Point &b)const{
        return x*b.x + y*b.y;
    }
    //返回两点的距离
    double dis(Point p){
        return hypot(x-p.x, y-p.y);
    }
    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);
    }
};

struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e){
        s = _s;
        e = _e;
    }
    // 点在线段上的判断
    bool pointonseg(Point p){
        return sgn((p-s)^(e-s)) == 0 && sgn((p-s) * (p-e)) <= 0;
    }

    // 求两直线的交点
    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));
    }
};

// 求点a和点b的中点
Point get_mid(Point a, Point b) {
    return (a + b) * 0.5;
}

// 根据三个点计算三角形面积
double area(Point a,Point b,Point c)
{
    return fabs((b - a) ^ (c - a) * 0.5);
}

void Solve() {
    Point a, b, c, p;
    Line ab, bc, ac;
    a.input(), b.input(), c.input(), p.input();
    ab = Line(a, b), ac = Line(a, c), bc = Line(b, c);
    double s1 = area(a, b, c) / 2;
    if (!ab.pointonseg(p) && !ac.pointonseg(p) && !bc.pointonseg(p)) {
        puts("-1\n");
        return;
    }
    if (ab.pointonseg(p)) {//ab
        if (a.dis(p) < b.dis(p)) {
            Point l = b, r = c;
            Point mid = get_mid(l, r);
            for (int i = 0; i < 50; i++) {
                mid = get_mid(l, r);
                double s2 = area(mid, p, b);
                int flag = sgn(s2 - s1);
                if (flag == 0) {
                    break;
                }
                else if (flag == 1) {
                    r = mid;
                }
                else {
                    l = mid;
                }
            }
            printf("%.10lf %.10lf\n", mid.x, mid.y);
        }
        else {
            Point l = a, r = c;
            Point mid = get_mid(l, r);
            for (int i = 0; i < 50; i++) {
                mid = get_mid(l, r);
                double s2 = area(mid, p, a);
                int flag = sgn(s2 - s1);
                if (flag == 0) {
                    break;
                }
                else if (flag == 1) {
                    r = mid;
                }
                else {
                    l = mid;
                }
            }
            printf("%.10lf %.10lf\n", mid.x, mid.y);
        }
    }
    else if (ac.pointonseg(p)) {//ac
        if (a.dis(p) < c.dis(p)) {
            Point l = c, r = b;
            Point mid = get_mid(l, r);
            for (int i = 0; i < 100; i++) {
                mid = get_mid(l, r);
                double s2 = area(mid, p, c);
                int flag = sgn(s2 - s1);
                if (flag == 0) {
                    break;
                }
                else if (flag == 1) {
                    r = mid;
                }
                else {
                    l = mid;
                }
            }
            printf("%.10lf %.10lf\n", mid.x, mid.y);
        }
        else {
            Point l = a, r = b;
            Point mid = get_mid(l, r);
            for (int i = 0; i < 50; i++) {
                mid = get_mid(l, r);
                double s2 = area(mid, p, a);
                int flag = sgn(s2 - s1);
                if (flag == 0) {
                    break;
                }
                else if (flag == 1) {
                    r = mid;
                }
                else {
                    l = mid;
                }
            }
            printf("%.10lf %.10lf\n", mid.x, mid.y);
        }
    }
    else {//bc
        if (b.dis(p) < c.dis(p)) {
            Point l = c, r = a;
            Point mid = get_mid(l, r);
            for (int i = 0; i < 50; i++) {
                mid = get_mid(l, r);
                double s2 = area(mid, p, c);
                int flag = sgn(s2 - s1);
                if (flag == 0) {
                    break;
                }
                else if (flag == 1) {
                    r = mid;
                }
                else {
                    l = mid;
                }
            }
            printf("%.10lf %.10lf\n", mid.x, mid.y);
        }
        else {
            Point l = b, r = a;
            Point mid = get_mid(l, r);
            for (int i = 0; i < 50; i++) {
                mid = get_mid(l, r);
                double s2 = area(mid, p, b);
                int flag = sgn(s2 - s1);
                if (flag == 0) {
                    break;
                }
                else if (flag == 1) {
                    r = mid;
                }
                else {
                    l = mid;
                }
            }
            printf("%.10lf %.10lf\n", mid.x, mid.y);
        }
    }
}

int main() {

    int T;
    scanf("%d", &T);
    rep (i, 0, T) {
        Solve();
    }

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值