3 条题解

  • 1
    @ 2024-12-12 23:22:44

    很明显这道题是一个差分题,但是要求我们判断断裂数组的最小时间,一个暴力的想法是每次都在轰炸的地方加上对应的杀伤力,如果有一个位置的杀伤力>=m,就输出对应的秒数,但是这种方法的时间复杂度为O(n^2),数据给的范围是1e5,我们可以想办法把他优化到O(nlogn),不妨换个角度思考,从答案的角度来看,我们需要找到一个最小数,也就是说答案可以理解为是递增的,根据logn的复杂度我们可以想到二分查找,即对答案进行二分查找,这样我们二分答案然后差分数组,就能得到时间复杂度为O(nlogn)的算法。 代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxv=1e5+10;
    #define ll long long
    ll n,m,lefts[maxv],rights[maxv],values[maxv],arr[maxv]={0};
    bool judge(int time){
    	memset(arr,0,sizeof(arr));//重置数组值为0
    	//此处差分为 
        for(int i=0;i<time;i++){
            arr[lefts[i]]+=values[i];
            arr[rights[i]+1]-=values[i];
        }
        ll maxv=*max_element(rights,rights+time);//找右边界最大值,缩短差分长度 
        //还原数组 
        for(int i=1;i<=maxv;i++){
            arr[i]+=arr[i-1];
            if(arr[i]>=m)return 1;//如果找到就返回true 
        }
        return 0;//否则返回false 
    }
    int main(){
    	ios_base::sync_with_stdio(0);
    	cin.tie(0);cout.tie(0);
        cin>>n>>m;
        for(int i=0;i<n;i++){
            cin>>lefts[i]>>rights[i]>>values[i];
        }
        int l=0,r=n;
        //二分答案,此处为左闭右闭写法
    	//int ans=0; 
        while(l<=r){
            int mid=l+(r-l)/2;
            if(judge(mid)){
            	//ans=mid若分不清l是答案还是r是答案可以再开一个ans记录 
                r=mid-1;
            }else{
                l=mid+1;
            }
        }
        if(l<=n)cout<<l;//若没有找到那么l一定会越界 
        else cout<<"impossible";
    	return 0;
    }
    

    时间复杂度O(nlogn); 空间复杂度O(n); 希望我的题解对你有帮助!

    信息

    ID
    965
    时间
    1000ms
    内存
    256MiB
    难度
    9
    标签
    递交数
    708
    已通过
    66
    上传者