新疆大学ACM新生赛(公开赛)

A hello world

签到

#include<bits/stdc++.h>
using namespace std;

string s="hello world";
int main(){
    for(int i=0;i<s.size();i++){
        cout<<char(s[i]+1);
    }
}

B 挂科

简单想一想就好了

#include<bits/stdc++.h>

using namespace std;

int main(){
    int n,x,y;
    cin>>n>>x>>y;
    cout<<min(x,y)<<" "<<max(0,x+y-n)<<endl;
}

C a+b

签到

#include<bits/stdc++.h>

using namespace std;

int main(){
    int a,b;
    cin>>a>>b;
    printf("%x",a+b);
}

D 数组的和

维护一下前缀和,然后扫一下即可

#include<bits/stdc++.h>

using namespace std;
const int N = 2e5+5;

long long pre[N],res=0;
int main(){
    int n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        long long x;
        cin>>x;
        pre[i]=pre[i-1]+x;
        if(i>=k){
            res=max(pre[i]-pre[i-k],res);
        }
    }
    cout<<pre[n]-res<<endl;
}

E 异或

题目描述:

给定一个长度为n初始全为0的数列ai,下标从1开始。定义操作模k异或v为对所有满足(i≡0(modk))的下标i,将异或上整数v(即令$ai=ai⊕v $)。

给出q次操作,每次操作之后输出序列的异或和,并且在操作结束之后输出整个序列。

思路:

对于所有输入,首先开一个数组维护所有模k的数需要异或的异或和,最后遍历(a_i),找出所有(a_i)的约数,异或上之前维护的这个异或和即可,复杂度为(O(n*sqrt{n}))

#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;
typedef long long LL;

int mp[N], a[N], n, q, k, v;

vector<int> get_divisors(int x) {
    vector<int> res;  // 记录答案
    for (int i = 1; i <= x /i; ++i) {  // 枚举到sqrtx(x)
        if (x % i == 0) {  // 如果能够整除
            res.push_back(i);  // 放入i
            if (i != x / i) res.push_back(x / i);  // x/i不等于i,也放入答案中
        }
    }
    return res;
}

int main(){
    cin >> n >> q;
    int sum = 0;
    for (int i = 1; i <= q; ++i) {
        scanf("%d%d", &k, &v);
        int cnt = n / k;
        if (cnt & 1) sum ^=v;
        printf("%d
", sum);
        if (k > n) continue;
        mp[k] ^= v;
    }
    for (int i = 1; i <= n; ++i) {
        vector<int> tmp = get_divisors(i);
        for (int j = 0; j < tmp.size(); ++j) a[i] ^= mp[tmp[j]];
    }
    for (int i = 1; i <= n; ++i)
        printf("%d ", a[i]);
        return 0;
}

F 最近的两个点

题目描述:

给定三维空间上n个点,每个点都有xi,yi,zi三个坐标值.找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的.

思路:

分治法,首先来看二维平面内最近的两个点问题。

现将所有的点按照X坐标排序,然后取中点,将其分为两个部分:

对于最近的点对,只可能有三种情况:

1.两个点都在左区间

2.两个点都在右区间

3.两个点分局mid的左右两侧

对于左右两个区间,我们可以通过分治的方法求出这个区间内的最近点对的距离,那么这时我们得到了(res=min(solve(l,mid),solve(mid+1,r)))

第三种情况怎么处理呢?因为我们已经得到了res代表两个区间中最近点对的距离,所以如果存在第三种情况,那么其x值必然在([mid-res,mid+res])之间,那么和他配对的点在哪呢?必然是以这个点为圆心,以res为半径画圆,只需要考虑这个圆内的点即可,经过下面的推导可以证明最多只有6个点可以何其配对,这样我们第三种情况在(O(n))的复杂度内就可以解决

证明最多只有6个点可以配对:

首先考虑极端情况,即该点正好在分界线 mid 上:

因为圆形难以分析,我们直接放缩到橙色矩形的情况,将矩形划分为6个部分,假设左侧有7个点位于橙色矩形内,那么根据抽屉原理,必然有两个点放在同一个小矩形内,而同一个小矩形内的点,其距离最大值为对角线距离即(r*sqrt{(2/3)^2+(1/2)^2}=5/6*r<r),也就是说这两个点的距离已经比当前求出的最小距离要小了,所以不可能有7个点,最多有6个点,所以我们直接将([mid-res,mid+res])内的点根据y值排序,然后枚举每个点,由于最多只有6个点能和当前枚举的点进行配对,所以枚举每个点进行更新的复杂度为(O(6*n))(O(n))

那么三维的怎么做呢?

因为分治的时候只是用了x作为分治的边界,跟y和x没有什么关系,所以直接在枚举的时候加上z的约束即可,其他都可以照抄~

#include<bits/stdc++.h>

using namespace std;

const int N = 1e5 + 5;
int n;
const double INF = 0x3f3f3f3f;
struct node
{
    double x, y, z;
}a[N];

bool cmpx(node a,node b){
    return a.x < b.x;
}

bool cmpy(node a,node b){
    return a.y < b.y;
}

double dis(node a,node b){
    return (sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z)));
}

double solve(int l,int r){
    if(l==r){
        return INF;    //当前区间只有一个点,返回INF,避免更新答案
    }
    int mid = l + r >> 1;   
    double midnum = a[mid].x;   //区间中点
    double res = min(solve(l, mid), solve(mid + 1, r));  //分治求两边区间的最小距离
    sort(a + l, a + r + 1, cmpy);      //按照y轴排序,这样后面在找的时候只需要找最近的几个点即可
    int temp[N], cnt = 0;
    for (int i = l; i <= r; i++){
        if(a[i].x>=midnum-res&&a[i].x<=midnum+res){
            temp[cnt++] = i;     //将“中间地带”的点加入temp,准备判断
        }
    }
    for (int i = 0; i < cnt;i++){
        for (int j = i - 1; j >= 0 && (a[temp[i]].y - a[temp[j]].y < res) && (a[temp[i]].z - a[temp[j]].z < res);j--)  //因为已经排好序了,所以只会遍历到最近的几个点,可以证明最多只有6个点,所以复杂度为O(n)
        {
            res = min(res, dis(a[temp[i]], a[temp[j]]));
        }
    }
    return res;
}

int main(){
    cin>>n;
    for (int i = 0; i < n;i++){
        cin >> a[i].x >> a[i].y >> a[i].z;
    }
    sort(a, a + n, cmpx);
    printf("%.3lf
",solve(0, n - 1));
    return 0;
}

参考:

https://www.acwing.com/solution/content/15774/

原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14028260.html