头像

_LRJ_

浙江大学




离线:5小时前


最近来访(332)
用户头像
huangbq
用户头像
无所谓我会补考
用户头像
这个人够厉害吗
用户头像
Ning0-0
用户头像
Archer1
用户头像
Jared_McDs
用户头像
超级熊_tongji
用户头像
刘睿健
用户头像
边吃边敲
用户头像
Archerr
用户头像
纽约州市长
用户头像
不会DP不改名de
用户头像
陈院士之名
用户头像
syyy
用户头像
puffan
用户头像
_LRJ__2
用户头像
算法小分队
用户头像
tonngw
用户头像
MrShuang
用户头像
Koschei


_LRJ_
4天前

题目描述

模拟季后赛。
已知有(1 << k)个队伍,team1实力最强,team2实力第2强,以此类推。赛制就是按照起始每个队伍的顺序开始两两对决,输的队伍直接淘汰,赢得进入下一轮,如下图所示,最终要求所有的队伍的位次按照右图的place(例如在n=8的时候,第一轮要淘汰5 6 7 8 第二轮要淘汰3 4,第三轮淘汰2)。现在给定的输入仅确定了部分位置的起始队伍是哪个,例如a[2] = 5,代表team5的初始位置确定了,为2a[i]=-1代表第i个起始位置没有确定下是哪支队伍。求安排其余未确定队伍的初始位置后满足题意的方案数。
tu


(模拟 + 组合数学计数) $O(n)$

直接模拟每一轮的对决,在特定的一轮,假设当前有n支队伍,按照题目要求,可以知道的是这一轮编号n/2+1到 n的队伍会淘汰,编号1到n/2的队伍晋级。那么问题转化为了,求这一轮要淘汰的队伍的所有确定位置的方案数量。
可以发现,当前两两对决的队伍构成了n/2个集合:
$\lbrace1, 2\rbrace, \lbrace3, 4\rbrace, … ,\lbrace n-1, n\rbrace$
如果编号n/2到n的队伍中已经确定了起始位置的两支队伍位于同一个集合,则输出0,因为本该淘汰的队伍会晋级,不符合题意。如果没有出现这样的情况,则对于所有的n/2个集合,必然有一个是编号为1到n/2和一个编号为n/2+1到n。那么只需要考虑编号n/2+1到n的队伍如何安排顺序,假设有其中有k个队伍是未定顺序的那么$res = res * k!$。同时,对于每一个集合,如果晋级的队伍位置没有定,那么被淘汰的队伍可以有两个方案(假设晋级的和淘汰的编号分别为$a, b$,则有$\lbrace a, b\rbrace$ 和$\lbrace b, a\rbrace$两种)。这时需要$res = res * 2$

时间复杂度

模拟了整个过程 时间复杂度是$O(n)$

C++ 代码

//#pragma GCC optimize(2)
#include<bits/stdc++.h>

using namespace std;
#define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0)
const int mo = 998244353;
typedef long long ll;

const int N = (1 << 19) + 10;
int n, a[N], k, pos[N], next_pos[N], na[N];
bool vis[N];
ll fac[N];

void init() {
    fac[0] = 1;
    fac[1] = 1;
    for (int i = 2; i < N; i ++) fac[i] = fac[i - 1] * i %mo;
}
void solve() {
    init();
    cin >> k;
    n = (1 << k);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        if (a[i] != -1) {
            pos[a[i]] = i;
            a[i] = 0;
        } else {
            a[i] = 1; //a[i] 代表位置i是否确定了队伍,1代表已经确定了放在这个位置的队伍,0 代表这个位置可以自己选择队伍放进去
        }
    }
    ll res = 1;
    while (n > 1) {
        for (int i = 1; i <= n / 2; i ++) {
            na[i] = a[i * 2 - 1] + a[i * 2]; //下一轮的第i组中对决的队伍有多少未确定的队伍
        }
        for (int i = 1; i <= n; i ++) {
            next_pos[i] = (pos[i] + 1) / 2;
        }

        for (int i = 1; i <= n / 2; i ++) vis[i] = false;
        int cnt = 0; // 这一轮被淘汰的队伍中 未确定顺序(seed)的队伍数量
        for (int i = n / 2 + 1; i <= n; i ++) {
            if (next_pos[i] == 0) {
                cnt ++;
                continue;
            }
            if (vis[next_pos[i]]) { //本轮 确定了起始位置(seed)的 且 要被淘汰 的队伍,如果其中有两支队伍进入下一轮的同一组,则输出0,因为不满足题意。
                cout << 0;
                return;
            }
            vis[next_pos[i]] = true;
        }
        res = res * fac[cnt] % mo;

        for (int i = 1; i <= n / 2; i ++) {
            if (!vis[i]) res = res * na[i] % mo, na[i] --; //vis[i] == false 代表下一轮第i组 中 在本轮被淘汰的队伍没有确定是哪支队伍
        }
        for (int i = 1; i <= n / 2; i ++) pos[i] = next_pos[i];
        for (int i = 1; i <= n / 2; i ++) a[i] = na[i];
        n /= 2;
    }
    cout << res;
}

int main() {
//    freopen("C:/Users/14842/CLionProjects/cf/in.txt", "r", stdin);
//    freopen("C:/Users/14842/CLionProjects/cf/out.txt", "w", stdout);
//    int tt;
//    cin >> tt;
//    while (tt --)
    solve();
    return 0;
}



_LRJ_
6天前



_LRJ_
7天前

题目描述

给你一个长度为n的数组,代表n道题目,每个题目有一个写题解的时间,选出长度为k的子序列,然后有两个人分别从前后选取一个前缀和后缀,并行完成写题解的过程,求两人都完成写题解的最短时间。

样例

输入

6
5 4
1 10 1 1 1
5 3
1 20 5 15 3
5 3
1 20 3 15 5
10 6
10 8 20 14 3 8 6 4 16 11
10 5
9 9 2 13 15 19 4 9 13 12
1 1
1

输出

2
6
5
21
18
1


二分 + 反悔堆

二分一下答案$mid$,并且分别求一下原数组的前缀和后缀不超过$mid$的情况下最多能选多少个题目。这里可以使用反悔堆来贪心地维护当前所选的数字,每一次将当前的数字加入优先队列,然后一直弹出堆顶元素(即堆中的最大元素)直到当前优先队列中元素值的总和不超过$k$,这样就可以求出在总和不超过$mid$的情况下,前缀和后缀分别最多能装下多少个元素。

时间复杂度

二分答案$O(log(1e15))$
每次check函数$O(nlogn)$
总的时间复杂度为$O(log(1e15) * n * logn)$

C++ 代码

//#pragma GCC optimize(2)
#include<bits/stdc++.h>

using namespace std;
#define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0)
const int mo = 998244353;
typedef long long ll;

int n, a[300010], k;
ll pre[300010], suf[300010];

bool check(ll mid) {
    suf[n + 1] = 0;
    priority_queue<ll> q;
    ll now = 0;
    for (int i = 1; i <= n; i ++) {
        q.push(a[i]);
        now += a[i];
        while (now > mid) {
            now -= q.top();
            q.pop();
        }
        pre[i] = int(q.size());
    }
    while (!q.empty()) q.pop();
    now = 0;
    for (int i = n; i >= 1; i --) {
        q.push(a[i]);
        now += a[i];
        while (now > mid) {
            now -= q.top();
            q.pop();
        }
        suf[i] = int(q.size());
    }
    for (int i = 0; i <= n; i ++) {
        if (pre[i] + suf[i + 1] >= k) return true;
    }
    return false;
}

void solve() {
    cin >> n >> k;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
    }

    ll l = 0, r = 1e15;
    while (l < r) {
        ll mid = l + r >> 1;
        if (check(mid)) {
            r = mid;
        } else l = mid + 1;
    }
    cout << l << "\n";
}

int main() {
//    freopen("C:/Users/14842/CLionProjects/cf/in.txt", "r", stdin);
//    freopen("C:/Users/14842/CLionProjects/cf/out.txt", "w", stdout);
    int tt;
    cin >> tt;
    while (tt --) solve();
    return 0;
}



_LRJ_
8天前



_LRJ_
26天前



_LRJ_
28天前



_LRJ_
1个月前

这题直接使用Java的TreeMap,维护已经输入的所有数值和对应的下标,再使用ceilingEntry()和floorEntry()分别求出和 当前值最接近的键值对,再进行求解即可。
值得注意的是本题一开始使用的是System.out.printf()输出TLE,换成System.out.println()能AC。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        TreeMap<Integer, Integer> treemap = new TreeMap<>();
        for (int i = 1; i <= n; i ++) {
            int x = sc.nextInt();
            if (i == 1) {
                treemap.put(x, i);
                continue;
            }
            Map.Entry<Integer, Integer> floor = treemap.floorEntry(x);
            Map.Entry<Integer, Integer> ceil = treemap.ceilingEntry(x);
            if (floor == null) {
                System.out.println(ceil.getKey() - x + " " + ceil.getValue());
            } else if (ceil == null) {
                System.out.println(x - floor.getKey()+ " " + floor.getValue());
            } else {
                if (x - floor.getKey() <= ceil.getKey() - x) {
                    System.out.println(x - floor.getKey() + " " + floor.getValue());
                } else {
                    System.out.println(ceil.getKey() - x + " " + ceil.getValue());
                }
            }
            treemap.put(x, i);
        }
    }
}


活动打卡代码 AcWing 136. 邻值查找

_LRJ_
1个月前
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        TreeMap<Integer, Integer> treemap = new TreeMap<>();
        for (int i = 1; i <= n; i ++) {
            int x = sc.nextInt();
            if (i == 1) {
                treemap.put(x, i);
                continue;
            }
            Map.Entry<Integer, Integer> floor = treemap.floorEntry(x);
            Map.Entry<Integer, Integer> ceil = treemap.ceilingEntry(x);
            if (floor == null) {
                System.out.println(ceil.getKey() - x + " " + ceil.getValue());
            } else if (ceil == null) {
                System.out.println(x - floor.getKey()+ " " + floor.getValue());
            } else {
                if (x - floor.getKey() <= ceil.getKey() - x) {
                    System.out.println(x - floor.getKey() + " " + floor.getValue());
                } else {
                    System.out.println(ceil.getKey() - x + " " + ceil.getValue());
                }
            }
            treemap.put(x, i);
        }
    }
}



_LRJ_
1个月前

System.out.printf()会TLE

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        TreeMap<Integer, Integer> treemap = new TreeMap<>();
        for (int i = 1; i <= n; i ++) {
            int x = sc.nextInt();
            if (i == 1) {
                treemap.put(x, i);
                continue;
            }
            Map.Entry<Integer, Integer> floor = treemap.floorEntry(x);
            Map.Entry<Integer, Integer> ceil = treemap.ceilingEntry(x);
            if (floor == null) {
                System.out.printf("%d %d\n", ceil.getKey() - x, ceil.getValue());
            } else if (ceil == null) {
                System.out.printf("%d %d\n", x - floor.getKey(), floor.getValue());
            } else {
                if (x - floor.getKey() <= ceil.getKey() - x) {
                    System.out.printf("%d %d\n", x - floor.getKey(), floor.getValue());
                } else {
                    System.out.printf("%d %d\n", ceil.getKey() - x, ceil.getValue());
                }
            }
            treemap.put(x, i);
        }
    }
}

换成System.out.println()能AC

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        TreeMap<Integer, Integer> treemap = new TreeMap<>();
        for (int i = 1; i <= n; i ++) {
            int x = sc.nextInt();
            if (i == 1) {
                treemap.put(x, i);
                continue;
            }
            Map.Entry<Integer, Integer> floor = treemap.floorEntry(x);
            Map.Entry<Integer, Integer> ceil = treemap.ceilingEntry(x);
            if (floor == null) {
                System.out.println(ceil.getKey() - x + " " + ceil.getValue());
            } else if (ceil == null) {
                System.out.println(x - floor.getKey()+ " " + floor.getValue());
            } else {
                if (x - floor.getKey() <= ceil.getKey() - x) {
                    System.out.println(x - floor.getKey() + " " + floor.getValue());
                } else {
                    System.out.println(ceil.getKey() - x + " " + ceil.getValue());
                }
            }
            treemap.put(x, i);
        }
    }
}



_LRJ_
1个月前
class Solution {
    public int NumberOf1(int n) {
        int res = 0;
        if (n < 0){
            res = 1;
            n = -n;
            n = n ^ (int)((1l << 31) - 1);
            n ++;
        }
        while (n > 0) {
            if ((n & 1) == 1) res ++;
            n >>= 1;
        }
        return res;
    }
}