2020省赛第八次训练赛题解

2020省赛第八次训练赛题解

前面的碎碎念

这场比赛的题目不是很难,签到题占了快一半了,同样的记录本场比赛的原因是因为本场比赛的思维题占了一半,思维题可遇不可求,每一次遇到都大开眼界,吐槽一下hdu和fzu竟然在国庆期间不开放,导致前面几场比赛没机会写题解,(其实也是没时间,每天一场训练赛对于我这种慢性子是需要很长很长很长的时间来补题的)你看看人家poj和zoj假期依然坚守岗位,在这里为两大oj点赞,当然牛客和洛谷也是坚守岗位。冲冲冲!!

A - Team Formation

思维题

题目分析:题目的意思就是有一些人,两两组队,每个人都有能力值,如果两个人能力值的异或值大于每一个人单独的能力值,那么这两个人组的队可以认为是一个出色的团队。

首先这个题目暴力是不会出奇迹的,暴力是可以过样例的但是显然也会超时,那么我们可以从异或出发,两个数的异或就是二进制的每一位异或,我们遵循相同为0,相异为1,也就是说如果两个数对应位置上的数字不同那么结果就是1,回到题目中,题目要求的是异或两个数之后变大,那么我们以其中一个数为基准,如果这个数二进制的某一位上为0,而对应另一个数相应位置并且这个位置是最高位二进制上为1,那么两个数异或就会变大,不用去考虑其他位,因为就算其他位置异或变小了但是我们保证高位异或变大整体还是变大的。

对于任意的a(以下用二进制来表示)
如a
1011001
对应的b可以是
1* * * * *
1* *
1*
对于b
若b的最高位 对于 a来说 在a的当前位 为0 则符合上述条件

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int vis[maxn], a[maxn];
int main()
{
   
    int t;
    scanf("%d", &t);
    while (t--)
    {
   
        int n;
        memset(vis, 0, sizeof(vis));
        scanf("%d", &n);
        ll ans = 0;
        for (int i = 1; i <= n; ++i)
        {
   
            scanf("%d", &a[i]);
            int x = a[i], tot = 0;
            while (x)
            {
   
                ++tot;
                x >>= 1;
            }
            vis[tot]++; //因为首位一定为1,那么就记录一下这个数最高位为1的位置
        }
        for (int i = 1; i <= n; ++i)
        {
   
            int x = a[i], tot = 0;
            while (x)
            {
   
                ++tot;
                if (!(x & 1)) //如果这个数当前位置为0,看看能找到几个数当前位置也是这个数二进制最高位为1
                              //并且这种过滤已经排除掉本身了,所以不用判断是不是异或本身
                    ans += vis[tot];
                x >>= 1;
            }
        }
        printf("%lld\n", ans);
    }
}

B - Convex Hull

计算几何,凸包

题意:给n个点,|x[i]|,|y[i]| <= 1e9。求在所有情况下的子集下(子集点数>=3),凸包的面积和。

这题主要有几个方面,一个是凸包的面积,可以直接用线段的有向面积和求得,这个当时没想到。还有就是,在180度以内的点数。

所以实际上是枚举2个点作为某个凸包的一条边,看有多少个这样的凸包。那个2^num - 1是保证除了2个点外至少还需1个点才能构成凸包。

时间复杂度O(n * n * logn)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;

const double pi = acos(-1.0);
#define ll long long
#define maxn 1010
#define mod 998244353
ll area2(ll ax, ll ay, ll bx, ll by)
{
   
    return ((ax * by % mod - ay * bx % mod) % mod + mod) % mod;
}
struct node
{
   
    ll x, y;
    double ang;
    bool operator<(const node &b) const
    {
   
        return ang < b.ang;
    }
} vec[maxn << 1];
ll p2[maxn];
int main()
{
   
    p2[0] = 1;
    for (ll i = 1; i <= 1000; ++i)
        p2[i] = (p2[i - 1] << 1) % mod;
    ll t;
    scanf("%lld", &t);
    while (t--)
    {
   
        ll n;
        scanf("%lld", &n);
        ll x[maxn], y[maxn];
        for (ll i = 0; i < n; ++i)
            scanf("%lld%lld", x + i, y + i);
        ll ans = 0;
        for (ll i = 0; i < n; ++i)
        {
   
            for (ll j = 0; j < n; ++j)
            {
   
                vec[j].x = x[j];
                vec[j].y = y[j];
                vec[j].ang = atan2(x[j] - x[i], y[j] - y[i]);
            }
            vec[i] = vec[n - 1];
            for (ll j = 0; j < n - 1; ++j)
            {
   
                vec[j + n - 1] = vec[j];
                vec[j + n - 1].ang += pi * 2;
            }
            ll nn = n - 1 + n - 1;
            sort(vec, vec + nn);
            ll l = 0, r = 0;
            while (l < n - 1)
            {
   
                while (r < nn && vec[r].ang - vec[l].ang < pi)
                    r++;
                ll area = area2(x[i], y[i], vec[l].x, vec[l].y);
                ll cnt = (p2[r - l - 1] - 1 + mod) % mod;
                ans = (ans + 1ll * area * cnt % mod) % mod;
                ++l;
            }
        }
        printf("%lld\n", (mod - ans) % mod);
    }
    return 0;
}

C - Beauty of Array

dp

参考链接

题目分析:这个题目很巧妙,题目要求的是所有连续序列中不同数字之和,出看可能不好写,也不知道怎么去写,暴力肯定会超时的,所以不用考虑。那么我们每添加一个元素进来,求当前序列包含a的所有序列之和,我们用两个变量dp,sum,dp去储存当前所有子序列的和,sum储存整个序列的和,然后用一个变量去定义每个数字最终出现的位置。

说是这么说,当我第一次看题解的时候,我没看懂,然后就自己手动模拟了一下代码的过程,大致模拟完之后,也就知道代码的意思了

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
typedef long long ll;
int a[maxn];
int main()
{
   
    int t, m, x;
    scanf("%d", &t);
    while (t--)
    {
   
        memset(a, 0, sizeof(a));
        scanf("%d", &m);
        ll ans = 0, dp = 0;
        for (int i = 1; i <= m
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值