cf1353D

cf1353D 1600的题
这题先说一下题意吧,就是给你一个n让你对这个长度为n且全为0的数组进行操作,首先是从这个数组中寻找含有0最多的一个区间,左右端点分别为l,r,如果r-l+1能整除2,那么这个数组a[(l+r-1)/2]=i,否则a[(l+r)/2] = i,这里的i指的是操作的次数,比如第一次进行操作的数相对来说是这个数组中间的位置,那么这个操作数就为1,之后进行递增。
首先可以看一下基本的模拟,肯定TLE的模拟
一个结构体表示该区间的0的个数ans和左端点l和右端点r,然后对其进行排序,之后ans最大的node里的l和r即为新的l和r,复杂度为O(n^2)。应该是挺好理解的

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 2e5+10;
struct node		//结构体用来存储左右端点和0的个数,方便之后的排序
{
    int ans, l, r;
    bool operator < (const node &x){
        if(x.ans==ans){
            return l<x.l;
        }else
        {
            return ans>x.ans;
        }
    }
};
int a[maxn];
int main(){
    ios::sync_with_stdio(0); 
    int t;
    cin>>t;
    while(t--){
        memset(a,0,sizeof(a));
        int x;cin>>x;
        int l = 1, r = x;
        for(int i = 1; i <= x; i++){
            if((r-l+1)%2==1){		//进行修改的点
                a[(l+r)/2] = i;		
            }else a[(l+r-1)/2] = i;
            node b[x+10];
            int k = 0;
            for(int j = 1; j <= x; j++){
                if(a[j]==0) b[k].l = j;		//左端点
                else continue;
                while(a[j]==0&&j<=x) j++;	//对0进行一个一个的遍历,最傻的方法。。。
                b[k].r = j-1;		//右端点
                b[k].ans = b[k].r-b[k].l+1;
                k++;
            }
            sort(b,b+k);
            l = b[0].l;r=b[0].r;
        }
        for(int i = 1; i <= x; i++){
            printf("%d ", a[i]);
        }
        printf("\n");
    }   
    return 0;
}

然后来一个进阶的方法,用vector进行包装,而且很显然的是不能像第一个模拟一样一个一个的遍历过去,所以这里用了区间的方式,对vector进行插入,但还是在2e5的时候TLE了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 2e5+10;
struct node
{
    int ans, l, r;
    bool operator < (const node &x){
        if(x.ans==ans){
            return l<x.l;
        }else
        {
            return ans>x.ans;
        }
    }
};
int a[maxn];
int main(){
    ios::sync_with_stdio(0); 
    int t;
    cin>>t;
    while(t--){
        memset(a,0,sizeof(a));
        int x;cin>>x;
        int l = 1, r = x;
        vector<node> v;
        for(int i = 1; i <= x; i++){
            int tmp;		//进行修改的点
            if((r-l+1)%2==1){	
                tmp = (l+r)/2;
                a[tmp] = i;
            }else tmp = (l+r-1)/2, a[tmp] = i;
            //当该点修改了之后,原本的区间就被拆分为了两个区间,把这两个区间放进vector中,即可得到这个点修改之后得到的结果							
            //然后再对vector进行一遍排序之后便可得到含有0最多的区间,并且要注意把这个为0的区间删去	
            v.push_back(node{tmp-l+1,l,tmp-1});		
            v.push_back(node{r-tmp+1,tmp+1,r});
            sort(v.begin(),v.end());
            l = v[0].l;r=v[0].r;
            v.erase(v.begin(), v.begin()+1);
        }
        for(int i = 1; i <= x; i++){
            printf("%d ", a[i]);
        }
        printf("\n");
    }   
    return 0;
}

最后一步的set大法,为什么会从vector到set呢,因为set和map的插入和删除都比其他的容器相对来说会快一点,而且事实证明也的确如此,而且set还会进行自动排序,最多是set里不能有重复的元素,但在这一题,显而易见的是不可能有相同的元素,所以也就不会漏掉,起码这题在2e5的地方过了,而且还是以300多ms过的,个人感觉还行,但应该不是最好的方法,后面还会再进行补充。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define INF 1ll<<60
const int maxn = 2e5+10;
struct node
{
    int ans, l, r;
    bool operator < (const node x) const{
        if(x.ans==ans){
            return l<x.l;
        }else
        {
            return ans>x.ans;
        }
    }
};
int a[maxn];
int main(){
    ios::sync_with_stdio(0); 
    int t;
    cin>>t;
    while(t--){
        memset(a,0,sizeof(a));
        int x;cin>>x;
        int l = 1, r = x;
        set<node> v;
        for(int i = 1; i <= x; i++){
            int tmp;
            if((r-l+1)%2==1){
                tmp = (l+r)/2;
            }else tmp = (l+r-1)/2; 
            a[tmp] = i;
            //这里的插入和删除和vector是一样的思路,但是比vector快
            v.insert(node{tmp-l+1,l,tmp-1});	
            v.insert(node{r-tmp+1,tmp+1,r});
            set<node>::iterator it;
            it = v.begin();
            l = (*it).l;r=(*it).r;
            v.erase(v.begin());
        }
        for(int i = 1; i <= x; i++){
            printf("%d ", a[i]);
        }
        printf("\n");
    }   
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值