bro,我写的二分+贪心check+线段树超时了,
查看原帖
bro,我写的二分+贪心check+线段树超时了,
1019606
KouMoSir楼主2024/3/10 09:28
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<utility>
#include<queue>
#include<cmath>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<pair<ll, ll>, ll> pa;
const ll N = 1e5 + 10, MOD = 722733748, INF = 0x7fffffffffffffff;

class cmp {
public:
    bool operator() (const pa& x, const pa& y)const {
        if (x.second != y.second)return x.second > y.second;
        else return 0;
    }
};
ll t, n, m, len, k;
ll con[4 * N], tag[4 * N];
deque<ll> indx, a;
void push_up(ll ind) {
    con[ind] = con[ind * 2] + con[ind * 2 + 1];
}
void push_down(ll ind) {
    if (tag[ind] == 0)return;
    con[ind * 2] = 0;
    tag[ind * 2] = tag[ind];
    con[ind * 2 + 1] = 0;
    tag[ind * 2 + 1] = tag[ind];
    tag[ind] = 0;
}
void build(int l, int r, int ind) {
    if (l == r) {
        // con[ind]代表了当前[L,R]中数的个数,这里是indx离散化之后的[L,R]
        con[ind] = 0;
        tag[ind] = -1;
        return;
    }
    ll mid = (l + r) / 2;
    build(l, mid, ind * 2);
    build(mid + 1, r, ind * 2 + 1);
    push_up(ind);
}
void udp(int l, int r, int ind, int tmpl, int tmpr) {
    if (l >= tmpl && r <= tmpr) {
        con[ind] = 0;
        tag[ind] = 1;
        return;
    }
    push_down(ind);
    ll mid = (l + r) / 2;
    if (mid >= tmpl)udp(l, mid, ind * 2, tmpl, tmpr);
    if (mid + 1 <= tmpr)udp(mid + 1, r, ind * 2 + 1, tmpl, tmpr);
    push_up(ind);
}
void udpp(int l, int r, int ind, int tmpl, int tmpr) {
    if (l >= tmpl && r <= tmpr) {
        con[ind]++;
        return;
    }
    ll mid = (l + r) / 2;
    push_down(ind);
    if (mid >= tmpl)udpp(l, mid, ind * 2, tmpl, tmpr);
    if (mid + 1 <= tmpr)udpp(mid + 1, r, ind * 2 + 1, tmpl, tmpr);
    push_up(ind);
}
ll query(int l, int r, int ind, int tmpl, int tmpr) {
    if (l >= tmpl && r <= tmpr) {
        return con[ind];
    }
    push_down(ind);
    ll mid = (l + r) / 2;
    ll res = 0;
    if (mid >= tmpl)res += query(l, mid, ind * 2, tmpl, tmpr);
    if (mid + 1 <= tmpr)res += query(mid + 1, r, ind * 2 + 1, tmpl, tmpr);
    push_up(ind);
    return res;
}
bool check(ll x) {
    ll cnt = 0;
    ll cntk = 1;
    // 线段树
    // udp用于全部清0
    // udpp用于单点增加1
    // query就是查询范围内的数量
    // check的思想就是不断贪心地去放入a原序列元素,然后统计逆序对个数
    udp(1, len, 1, 1, len);
    for (int i = 1; i <= n; i++) {
        ll tmp = upper_bound(indx.begin(), indx.end(), a[i]) - indx.begin();
        // tmp是比第一个比当前数大的位置
        ll num = 0;
        if (tmp <= len)num = query(1, len, 1, tmp, len);
        // 每次加入一个数,就加上能和该数形成逆序对的数量num
        if (cnt + num > x) {
            // 如果逆序对大于x,也就是目标,我就贪心地重新开一个段
            cntk++;
            // 如果段的数量大于题目k的限制,说明x不可满足,返回0
            if (cntk > k)return 0;
            // 可以继续开一个新段,就将线段数全部清0
            // 加入当前点
            udp(1, len, 1, 1, len);
            udpp(1, len, 1, tmp - 1, tmp - 1);
            cnt = 0;
        }
        else {
            cnt += num;
            udpp(1, len, 1, tmp - 1, tmp - 1);
        }
    }
    //最后如果全部放进去了,就表示x可以满足
    return 1;
}
void solve() {
    cin >> n >> k;

    a.clear();
    indx.clear();
    a.resize(n + 1);
    indx.resize(n + 1);

    // a数组是储存原序列,indx数组是储存排序后的序列,离散化
    for (int i = 1; i <= n; i++)cin >> a[i], indx[i] = a[i];
    sort(indx.begin() + 1, indx.end());
    len = unique(indx.begin() + 1, indx.end()) - indx.begin() - 1;
    build(1, len, 1);

    // 二分查找,查找满足check的最小数
    ll l = 0, r = n * (n - 1) / 2;
    while (l < r) {
        ll mid = (l + r) / 2;
        if (check(mid))r = mid;
        else l = mid + 1;
    }
    cout << l << '\n';
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    // t = 1;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
/*
*/

TLE了

不是WA,我的思路应该没错?

顺便问一下为什么只能得到一个测试点结果TLE

过一段时间后会更新吗,还是一直不能查看

2024/3/10 09:28
加载中...