【牛客练习赛11】A B D E

本文介绍了解决特定线段树更新与查询问题的方法,并给出了一次交换后排列中最值距离的最大化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A 假的线段树
链接:https://www.nowcoder.com/acm/contest/59/A
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给你一个长为n的序列a,有m次操作
1.把区间[l,r]内所有x变成y
2.查询区间[l,r]内第k小值
输入描述:
第一行两个数n,m
第二行n个数表示序列a
后面m行
1 l r x y :把区间[l,r]中所有x变成y
2 l r k :查询区间[l,r]中的第k小值
输出描述:
对于每个询问,输出一个数表示答案
示例1
输入

3 3
2 3 3
2 1 3 1
1 1 3 3 1
2 1 3 2
输出

2
1
备注:
对于100%的数据,1 <= n, m , ai <= 1000
题解: 看数据范围,操作一 暴力没有问题。操作二 ,我们可以用一个容器有序存储所截序列,然后找到第k项就行了。这里要用mutiset ,因为有重复数据。

代码

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

const int MAXN = 1e3+11;
int a[MAXN];
multiset<int>S;
multiset<int>::iterator it;
int main() {
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    while(m--){
        int l,r,op,x,y;
        scanf("%d%d%d%d",&op,&l,&r,&x);
        if(op==1){
            scanf("%d",&y);
            for(int i=l;i<=r;i++){
                if(a[i]==x) a[i]=y;
            }
        }else {
            S.clear();
            for(int i=l;i<=r;i++){
                S.insert(a[i]);
            }
            int i=1;
            for(it=S.begin();it!=S.end();it++,i++){
              if(i==x) {
                   cout<<*(it)<<endl;
                   break;
              }
            }
        }
    }
    return 0;
}

B 假的字符串
题解链接

D 求距离
链接:https://www.nowcoder.com/acm/contest/59/D
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给你一个1 -> n的排列,现在有一次机会可以交换两个数的位置,求交换后最小值和最大值之间的最大距离是多少?
输入描述:
第一行一个数n
之后一行n个数表示这个排列
输出描述:
输出一行一个数表示答案
示例1
输入

5
4 5 1 3 2
输出

3
说明

把1和2交换后
序列为4 5 2 3 1
最大值5在数组的2位置,最小值1在数组的5位置
距离为3
备注:
对于100%的数据,1 <= n <= 100

水题
代码

#include<bits/stdc++.h>
using namespace std;
const int inf  = 0x3f3f3f3f;

const int MAXN = 1e3+11;
int arr[MAXN];
struct node{
    int pos,num;
}mx,mn;
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        mx.num=-1;   mn.num=inf;
        for(int i=0;i<n;i++){
            scanf("%d",&arr[i]);

            if(arr[i]<mn.num){
                mn.num=arr[i];
                mn.pos=i;
            }
            if(arr[i]>mx.num){ mx.num=arr[i];mx.pos=i; }
        }
        int x = max(abs(n-1-mn.pos),abs(mn.pos));
        int y = max(abs(n-1-mx.pos),abs(mx.pos));


        printf("%d\n",max(x,y));
    }
    return 0;
}

E 求最值
链接:https://www.nowcoder.com/acm/contest/59/E
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给你一个长为n的序列a
定义f(i,j)=(i-j)2+g(i,j)2
g是这样的一个函数
这里写图片描述
求最小的f(i,j)的值,i!=j

输入描述:
第一行一个数n
之后一行n个数表示序列a
输出描述:
输出一行一个数表示答案
示例1
输入

4
1 0 0 -1
输出

1
备注:
对于100%的数据,2 <= n <= 100000 , |ai| <= 10000

分析:cf原题,把题目公式变形一下 ,就好看了
f(i,j) = (j-i)^2 + (sum[j] - sum[i] ) ^2
距离公式,所以就是求最近点对问题
代码

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

const int MAXN = 100000 + 10;
const int MAXM = 1e6;
const int mod = 1e9+7;
const LL inf = 0x3f3f3f3f3f3f3f;

struct Node{
    LL x,y;
}Point[MAXN],Q[MAXN];
bool cmpx(Node a,Node b) { return a.x<b.x ; }
bool cmpy(Node a,Node b){ return a.y<b.y ; }
LL sqr(LL a) { return a*a;  }
LL GetDis(Node a,Node b){ return sqr(a.x-b.x)+sqr(a.y-b.y); }
LL DIV(int le,int ri){
    LL ret=inf;
    if(le==ri) return ret;
    if(le+1==ri) return GetDis(Point[le],Point[ri]);
    int mid=(le+ri)>>1;
    LL d1=DIV(le,mid);
    LL d2=DIV(mid+1,ri);
    ret=min(d1,d2);
    double d=sqrt((double)ret);
    int k=0;
    for(int i=mid;i>=le;i--) {
        if(Point[mid].x-Point[i].x>(LL)d) break;
        Q[++k]=Point[i];
    }
    for(int i=mid+1;i<=ri;i++) {
        if(Point[i].x-Point[mid].x>(LL)d) break;
        Q[++k]=Point[i];
    }
    sort(Q+1,Q+1+k,cmpy);
    for(int i=1;i<k;i++){
        for(int j=i+1;j<=k&&Q[j].y-Q[i].y<=(LL)d;j++)
        ret=min(ret,GetDis(Q[j],Q[i]));
    }
    return ret;
}
int a[MAXN];
int main(){
    int n;scanf("%d",&n);
    LL sum=0;
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        sum+=a[i];
        Point[i].x=i;
        Point[i].y=sum;
    }
    sort(Point+1,Point+1+n,cmpx);
    printf("%lld\n",DIV(1,n));
    return 0;
}

还有就是 可以暴力 我们可以暴力个几千个点 也是可以过的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值