2019 ICPC Asia Nanjing Regional

题目地址

A题

  • 题意
    在这里插入图片描述

  • 思路
    就找最大的集合,不存在 2 2 2 倍关系的那个就是答案。

  • 代码

	int n;cin>>n;
	if (n % 2 == 0) {
		cout << n/2+1 <<endl;
	} else {
		cout << n/2+2 <<endl; 
	}

H题

  • 题意
    王子想要娶公主,但是需要完成一个挑战:在一些房间中找出公主在哪。

每个房间有一个人,他们彼此知道谁在哪个房间。可以问他们三种问题:

  • 你是谁?
  • 在某个房间是谁?
  • 公主在哪个房间?
    有三类人,一类一定说真话,一类一定说假话,一类可能说真话可能说假话。

王子知道这三类人的人数分别为 a, b, c,求能否通过问一些问题找到公主在哪,如果能,输出最少需要的问题数。

  • 思路
    太狗了吧这题
    1 , 0 , 0 1,0,0 1,0,0 这种情况为啥不用问就可以了,这也太好了吧,难道公主直接看着没有人反对直接找他去了嘛。呜呜呜
  • 代码
	if (!b&&!c&&a==1) {
        cout<<"YES"<<endl;
        cout<<0<<endl; return;
    }//死活没想到
	if (a <= b+c) {
    	cout<<"NO"<<endl;
    } else {
		cout<<"YES"<<endl;
		cout<<2*(b+c)+1<<endl;
	}

在这里插入图片描述
这要是在比赛中不得被队友打死。

K题

  • 题意
    在这里插入图片描述
  • 思路
    这就是个简单几何题。
    如果 A A A 点不在三角形的三边,那么就是 − 1 -1 1 ;如果在的话,可以知道必有解。然后如果点 A A A 在边 a c ac ac 上,如果 a A aA aA > A c Ac Ac,那么点 B B B 可以确定在某一条边上,因此面积的变化具有单调性,所有可以二分处理。
  • 代码
#include <bits/stdc++.h>

using namespace std;

int n, m, T;

// 计算几何模板
const double eps = 1e-8;
// 和0做比较
int sgn(double x) {
    if (fabs(x) < eps) return 0;  // =0
    if (x < 0)
        return -1;  // < 0
    else
        return 1;  // > 0
}

struct Point {
    double x, y;
    Point() {}
    Point(double _x, double _y) {
        x = _x;
        y = _y;
    }
    void input() { scanf("%lf%lf", &x, &y); }
    void output() { printf("%.10f %.10f\n", x, y); }
    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.y - y * b.x; }
    //点积
    double operator*(const Point &b) const { return x * b.x + y * b.y; }
    //返回向量长度
    double len() {
        // hypot(x, y), 即sqrt(x * x + y * y)
        return hypot(x, y);  //库函数
    }
    //返回两点的距离
    double distance(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); }
    //计算pa和pb的夹角, 就是求这个点看a,b 所成的夹角的弧度
};

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

double getarea(Point a, Point b, Point c) {
    double sum = 0;
    sum += a.operator^(b) + b.operator^(c) + c.operator^(a);
    return fabs(sum) / 2;
}

Point get_mid(Point l, Point r) {
    return (l + r) * 0.5;
}

int main() {
    Point a, b, c, e, s;
    Line ab, bc, ac;
    cin >> T;
    while (T--) {
        a.input(), b.input(), c.input(), e.input();
        double tran_area = getarea(a, b, c) / 2;
        ab = Line(a, b), bc = Line(b, c), ac = Line(a, c);
        if (!ab.pointonseg(e) && !ac.pointonseg(e) && !bc.pointonseg(e)) {
            puts("-1");
            continue;
        }
        if (ab.pointonseg(e)) {
            double ae = a.distance(e), eb = b.distance(e);
            if (ae > eb) {
                Point l = a, r = c;
                Point mid = get_mid(l, r);
                int time = 1000;
                while (time--) {
                    mid = get_mid(l, r);
                    int flg = sgn(getarea(a, e, mid) - tran_area);
                    if (flg == 0) break;
                    else if (flg > 0) r = mid;
                    else l = mid;  
                }
                mid.output();
            } else {
                Point l = b, r = c;
                Point mid = get_mid(l, r);
                int time = 1000;
                while (time--) {
                    mid = get_mid(l, r);
                    int flg = sgn(getarea(b, e, mid) - tran_area);
                    if (flg == 0) break;
                    else if (flg > 0) r = mid;
                    else l = mid;  
                }
                mid.output();
            }
        } else if (bc.pointonseg(e)) {
            double be = b.distance(e), ce = c.distance(e);
            if (be > ce) {
                Point l = b, r = a;
                int time = 1000;
                Point mid = get_mid(l, r);
                while (time--) {
                    mid = get_mid(l, r);
                    int flg = sgn(getarea(b, e, mid) - tran_area);
                    if (flg == 0) break;
                    else if (flg > 0) r = mid;
                    else l = mid;
                }
                mid.output();
            } else {
                Point l = c, r = a;
                int time = 1000;
                Point mid = get_mid(l, r);
                while (time--) {
                    mid = get_mid(l, r);
                    int flg = sgn(getarea(e, c, mid) - tran_area);
                    if (flg == 0) break;
                    else if (flg > 0) r = mid;
                    else l = mid;
                }
                mid.output();
            }
        } else if (ac.pointonseg(e)) {
            double ae = e.distance(e), ec = c.distance(e);
            if (ae < ec) {
                Point l = c, r = b;
                Point mid = get_mid(l, r);
                int time = 1000;
                while (time--) {
                    mid = get_mid(l, r);
                    int flg = sgn(getarea(e, c, mid) - tran_area);
                    if (flg == 0) break;
                    else if (flg > 0) r = mid;
                    else l = mid;
                }
                mid.output();
            } else {
                Point l = a, r = b;
                Point mid = get_mid(l, r);
                int time = 1000;
                while (time--) {
                    mid = get_mid(l, r);
                    int flg = sgn(getarea(e, a, mid) - tran_area);
                    if (flg == 0) break;
                    else if (flg > 0) r = mid;
                    else l = mid;
                }
                mid.output();
            }
        }
    }
    return 0;
};

  • 代码2
#include <bits/stdc++.h>
using namespace std;
typedef double ld;
ld eps = 1e-8;

struct Point{
    ld x, y;
}a, b, c, p, q;
ld area;
ld ab, ac, bc, ap, bp;

bool onSegment(Point Pi, Point Pj, Point Q)
{
    if((Q.x - Pi.x) * (Pj.y - Pi.y) == (Pj.x - Pi.x) * (Q.y - Pi.y)  //叉乘
       //保证Q点坐标在pi,pj之间
       && min(Pi.x , Pj.x) <= Q.x && Q.x <= max(Pi.x , Pj.x)
       && min(Pi.y , Pj.y) <= Q.y && Q.y <= max(Pi.y , Pj.y))
        return true;
    else
        return false;
}

ld dist(Point a, Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool check(ld mid, ld sinb)
{
    ld are = sinb*(bp)*(bc-mid)/2;
    if(are*2.0 >= area) return 0;
    return 1;
}

void solve()
{
    scanf("%lf%lf%lf%lf%lf%lf%lf%lf", &a.x, &a.y, &b.x, &b.y, &c.x, &c.y, &p.x, &p.y);
    //cin>>a.x>>a.y>>b.x>>b.y>>c.x>>c.y>>p.x>>p.y;
    if(!onSegment(a, b, p)&&!onSegment(b, c, p)&&!onSegment(a, c, p))
    {
        puts("-1");
        return;
    }

    //先看看会不会在某个点上
    if(p.x == a.x && p.y == a.y)
    {
        //输出bc中点
        q.x = (b.x+c.x)/2.0;
        q.y = (b.y+c.y)/2.0;
        //cout << setprecision(10) << q.x << " " << q.y << endl;
        printf("%.10f %.10f\n", q.x, q.y);
        return;
    }
    else if(p.x == b.x && p.y == b.y)
    {
        //ac中点
        q.x = (a.x+c.x)/2.0;
        q.y = (a.y+c.y)/2.0;
        //cout << setprecision(10) << q.x << " " << q.y << endl;
        printf("%.10f %.10f\n", q.x, q.y);
        return;
    }
    else if(p.x == c.x && p.y == c.y)
    {
        //ab中点
        q.x = (a.x+b.x)/2.0;
        q.y = (a.y+b.y)/2.0;
       // cout << setprecision(10) << q.x << " " << q.y << endl;
        printf("%.10f %.10f\n", q.x, q.y);
        return;
    }


    //把点弄到ab上
    if(onSegment(a, b, p)) {}
    else if(onSegment(b, c, p)) swap(a, c);
    else if(onSegment(a, c, p)) swap(b, c);

    //距离b更近一点
    if(dist(a, p) > dist(b, p)) swap(a, b);

    //开始搞
    ab = dist(a, b);
    ac = dist(a, c);
    bc = dist(b, c);
    ap = dist(a, p);
    bp = dist(b, p);

    ld p = (ab+bc+ac)/(ld)2.0;
    area = sqrt(p*(p-ab)*(p-bc)*(p-ac));
    ld sina = area*2/ab/bc;
    //area = ab*bc*sinb/2
    //sina = area*2/ab/bc

    ld l = 0.0, r = bc;
    while(l+eps < r)
    {
        ld mid = (l+r)/(ld)2.0;
        if(check(mid, sina)) r = mid;
        else l = mid;
    }

    ld len = l;
    //输出点
    q.x = (b.x-c.x)*len/bc+c.x;
    q.y = (b.y-c.y)*len/bc+c.y;
    //cout << setprecision(10) << q.x << " " << q.y << endl;
    printf("%.10f %.10f\n", q.x, q.y);
    return;
}

int main()
{
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}

C题

  • 题意
    找满足题意的路径的数目。
  • 思路
    相邻的两个点如果权值相差为 1 1 1,则从小的向大的连边。然后最终连成的是一个 D A G DAG DAG,在 D A G DAG DAG 上面按照拓扑序 D P DP DP 即可。
  • 代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 1010, mod = 1e9 + 7;

typedef pair<int,int> pii;

int n, m;
int g[N][N], in[N][N], out[N][N], f[N][N][5];
int dx[4] = {0,1,0,-1}, dy[4] = {1,0,-1,0};

void topsort()
{
    queue<pii> que;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(!in[i][j])
            {
                que.push({i,j});
                f[i][j][1] = 1;
            }
    
    while(que.size())
    {
        auto t = que.front();
        que.pop();
        int x = t.first, y = t.second;
        for(int i=0;i<4;i++)
        {
            int tx = x + dx[i], ty = y + dy[i];
            if(tx<1||tx>n||ty<1||ty>m) continue;
            if(g[tx][ty]==g[x][y]+1)
            {
                f[tx][ty][2] = (f[tx][ty][2] + f[x][y][1]) % mod;
				f[tx][ty][3] = (f[tx][ty][3] + f[x][y][2]) % mod;
				f[tx][ty][4] = (f[tx][ty][4] + f[x][y][3] + f[x][y][4]) % mod;
				if(--in[tx][ty]==0)	que.push({tx,ty});
            }
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&g[i][j]);
    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=0;k<4;k++)
            {
                int tx = i + dx[k], ty = j + dy[k];
                if(tx<1||tx>n||ty<1||ty>m) continue;
                if(g[tx][ty]==g[i][j]+1) out[i][j] ++;
                if(g[tx][ty]==g[i][j]-1) in[i][j] ++;
            }
    
    int res = 0;
    topsort();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(!out[i][j])
                res = (res + f[i][j][4]) % mod;
    
    printf("%d\n",res);
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的码泰君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值