SDUT 2020 Summer Individual Contest - 5(for 19) Div.1

这几天家里接二连三的下雨导致我有点感冒,比赛前有点头晕,但是这对比赛好像没有很大的影响。

因为比赛开始后,所有不舒服的感觉都忘记了,可能这就是竞赛的魅力所在吧。

比赛前一半时间,就a了一道水题(还WA了一次),其他的题目不是阅读量就很大,就是没有思路。

所以最后也是勉勉强强的做出来3道题,原本自我感觉还良好,可是比赛结束后,看见了所有比赛的总榜,才知道被吊锤了...

其实也好,知道了和大佬的差距。

话不多说,先看我a的题目吧

J - Time Limit   题目链接 

题目大意:在CCPC竞赛中,会出现Time Limit的错误,这是超出时间限制。出题人要设置题目的时间限制x,并且自己先写出一个代码,保证自己的代码可以正常运行,而且运行代码的时间a1,满足x > 3 * a1。然后有n-1个其他正确的代码ai,要保证x > ai。最后,x必须是满足上述条件的最小偶数。

没错,这个就是那个水题,唯一的难度可能就是题面的翻译吧...就这样的题我还WA了一次...(心态爆炸)

思路:其实也不算有什么思路,就是找3 * a1和n-1个ai + 1中最大的。最后再变成最小的偶数。

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int x, n, ans = 0;
        cin >> n >> x;
        ans = 3 * x;
        for (int i = 1; i < n; i++)
        {
            cin >> x;
            ans = max(ans, x + 1);
        }
        ans += ans % 2 == 0 ? 0 : 1;
        cout << ans << endl;
    }
    return 0;
}

G - Radar Scanner  题目链接

题目大意:有n个平行于坐标轴的矩形,会输入矩形左下角和右上角的方块坐标,可以平行于x轴或y轴移动一个单位,询问要求这n个矩形至少交于一点最少的操作数是多少。

注意题目要求输入的是方块的坐标,不要思维惯性的想成是点的坐标。总体来说,题目理解起来不算难,但是如果真动手开始做,就不知道从何下手了...

思路:其实我们完全可以把方块看成一个点(x,y),意思就是找一个点到所有矩形的距离加和最小(反向分析就是把所有矩形移动到点(x,y),移动的距离最小,满足题意)。x和y轴方向的移动的思路都一样(要先移动到坐标x位置,再移动到y位置),所以我们可以选择其中一个方向来分析。对于x轴方向上移动来说,每条线段到x的距离为 (abs(A-x)+abs(B-x)-abs(A-B))/ 2,把所有线段到x的距离加起来就是\sum(abs(Ai-x)+abs(Bi-x)-abs(Ai-Bi))/ 2(i:0~n-1),\sumabs(Ai-Bi)是所有线段的长度,为一个定值。所以说,题目又能变成求所有点到x的最小距离,就是求所有\sumabs(Ai-x)+abs(Bi-x)最小,很显然当x是所有A,B的中位数的时候最小。

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxx = 1e6 + 100;
ll x[maxx], y[maxx];
int n, t;
int main()
{
    ios::sync_with_stdio(0);
    cin >> t;
    while (t--)
    {
        cin >> n;
        ll ans = 0;
        ll xx1, xx2, yy1, yy2;
        for (int i = 0; i < n; i++)
        {
            cin >> xx1 >> yy1 >> xx2 >> yy2;
            ans -= yy2 - yy1 + xx2 - xx1;
            x[i] = xx1;
            x[i + n] = xx2;  //因为只有n个数据,我们可以把xx2和yy2放在n个数后边
            y[i] = yy1;
            y[i + n] = yy2;
        }
        sort(x, x + 2 * n);//对所有的xx排序
        sort(y, y + 2 * n);//对所有的yy排序
        ll xx = x[n - 1], yy = y[n - 1];//中位数
        for (int i = 0; i < 2 * n; i++)
            ans += abs(x[i] - xx) + abs(y[i] - yy);//计算每个xxi和yyi到中位数的距离
        printf("%lld\n", ans / 2);
    }
}

C - Line-line Intersection 题目链接

题目大意:输入n组数据,每个数据包括一条直线上的两个点,找出来有多少对直线相交

这道题我一开始尝试了一下,感觉不会很简单,要考虑的情况很多,所以我就先放了一放,做完G题以后发现已经有人a了,所以就继续整理了思路。

思路:题目给的数据都不小,每个坐标的绝对值大小都<=1e9,所以我们要用map来模拟一下。中学生都知道的知识,两条直线,想要有交点,就必须斜率不同。另外,题目说明两条相同的直线,也算是有交点。所以我们在用map记住斜率的时候一定要特别注意这种情况,我们知道一条直线的一般方程是y=kx+b,所以,判断两条有相同斜率的直线是不是同一条,就可以看一下b=y-kx的值,要求输入直线上的坐标,所以b不难求。

k = 1.0 * (y1 - y2) / (x1 - x2);
b = y1 - k * x1;

注意注意注意,我们在中学做一些关于直线的题目的时候,都会想到一种特殊的直线,就是垂直x轴的直线,这样的直线x1==x2,所以k的大小就没有办法用这个公式来求。当时我做的时候也是忘了这一茬,所以就WA了一两次。我再一看题目,每个坐标的绝对值大小都<=1e9,而且都是整数,所以在不考虑上述情况下,|k|<=(1e9+1e9)/1,我看索性把斜率不存在的情况中的k记为2e9+1,b就记为x1。然后这种情况就可以和正常的情况一起做了。然后,我们知道如果有n条斜率不同的线,他们的交点有(n-1) + (n-2) + ... + 2 + 1 = n * (n - 1) / 2 个。先写个函数:

ll mul(ll n)
{
    return n * (n - 1) / 2;
}

我们用mp[k]++来记住有多少条直线的斜率为k,再用mp1[make_pair(k, b)]++来记住斜率相同的时候会不会有同一条直线的情况。假设每条直线的斜率都不同ans = mul(n),然后减去k相同的直线不能形成的交点,当然也必须是mul(n1),还要加上k相同b相同的情况mul(n2)。

说得有点多,代码如下:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const double maxx = 2e9 + 10;
map<double, ll>mp;
map<int, double>mk;
map<int, double>mb;
map<pair<double, double>, ll> mp1;
ll mul(ll n)
{
    return n * (n - 1) / 2;
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        mp.clear();
        mk.clear();
        mb.clear();
        mp1.clear();
        ll n;
        scanf("%lld", &n);
        for (int i = 0; i < n; i++)
        {
            double x1, x2, y1, y2;
            double k, b;
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            if (x1 == x2)
            {
                k = maxx;
                b = x1;
            }
            else
            {
                k = 1.0 * (y1 - y2) / (x1 - x2);
                b = y1 - k * x1;
            }
            mp[k]++;
            mk[i] = k;
            mb[i] = b;
            mp1[make_pair(k, b)]++;

        }
        ll sum = 0;
        for (int i = 0; i < n ; i++)
        {
            if (mp[mk[i]] > 1)
            {
                sum += mul(mp[mk[i]]);
                mp[mk[i]] = 0;
            }
        }
        for (int i = 0; i < n ; i++)
        {
            if (mp1[make_pair(mk[i], mb[i])] > 1)
            {
                sum -= mul(mp1[make_pair(mk[i], mb[i])]);
                mp1[make_pair(mk[i], mb[i])] = 0;
            }
        }
        ll ans = mul(n) - sum ;
        cout << ans << endl;
    }
    return 0;
}

这个代码只是我比赛时候的代码,当时做的慌,可能很多地方可以优化。而且方法比较笨,只是模拟。

下面这个是和我一个队的大佬的代码:

 明显比我的要好不少,他的思路是两个map一个存斜率,一个存是否重合,因为坐标都是int所以将Δx和Δy同除他们的gcd就可以 唯一表示斜率。yyds!!!

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const ll inf = 0xfffffff;
const ll N = 5e4 + 9;
map<pair<pair<ll, ll>, pair<ll, ll> >, ll> ma;
map<pair<ll, ll>, ll> k;
ll gcd(ll a, ll b)
{
    return b ? gcd(b, a % b) : b;
}
int main()
{
    ll t;
    ios::sync_with_stdio(0);
    cin >> t;
    while (t--)
    {
        ll n;
        k.clear();
        ma.clear();
        cin >> n;
        ll ans = 0;
        ll same = 0;
        for (ll i = 1; i <= n; i++)
        {
            ll x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            ll x = (x1 - x2), y = (y1 - y2);
            ll gcd_ = __gcd(x1 - x2, y1 - y2);
            pair<ll, ll> p1;
            p1.first = (x1 - x2) / gcd_, p1.second = (y1 - y2) / gcd_;
            k[p1]++;
            pair<ll, ll> p2;
            p2.first = p1.first * y1, p2.second = p1.second * x1;
            ma[ {p1, p2}]++;
            ans += i - 1 - k[p1] + ma[ {p1, p2}];
        }
        cout << ans << endl;
    }
    return 0;
}

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个简单的学生集合的示例代码,您可以参考: ```c++ #include <iostream> #include <string> #include <vector> using namespace std; class Student { private: string name; int age; double score; public: Student(string n, int a, double s) : name(n), age(a), score(s) {} string getName() const { return name; } int getAge() const { return age; } double getScore() const { return score; } }; class StudentCollection { private: vector<Student> students; public: void addStudent(Student s) { students.push_back(s); } void removeStudent(Student s) { for (vector<Student>::iterator it = students.begin(); it != students.end(); ++it) { if (it->getName() == s.getName()) { students.erase(it); break; } } } void printStudents() const { for (vector<Student>::const_iterator it = students.begin(); it != students.end(); ++it) { cout << "Name: " << it->getName() << ", Age: " << it->getAge() << ", Score: " << it->getScore() << endl; } } }; int main() { StudentCollection sc; sc.addStudent(Student("Tom", 18, 90)); sc.addStudent(Student("Jerry", 20, 80)); sc.addStudent(Student("Alice", 19, 85)); sc.printStudents(); sc.removeStudent(Student("Jerry", 20, 80)); sc.printStudents(); return 0; } ``` 这个示例代码中,定义了一个 `Student` 类和一个 `StudentCollection` 类。其中 `Student` 类表示一个学生,包括学生姓名、年龄、分数等信息。`StudentCollection` 类表示一个学生集合,包括添加学生、删除学生、打印学生信息等操作。在 `main` 函数中,演示了如何使用 `StudentCollection` 类来管理学生集合。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值