自学内容网 自学内容网

Bessie and MEX

题目链接

CodeTON Round 8 (Div. 1 + Div. 2, Rated, Prizes!)

B. Bessie and MEX


思路1(逆推):

注意看, p p p 数组是个排列,所以 0 ∼ n − 1 0\sim n-1 0n1 的所有数都会且只会出现一次。最后的 m e x mex mex 值一定是 n n n。我们正着推过去很难,但是倒推就会很简单,因为我们不知道 p i p_i pi 但是知道 m e x { p 1 , p 2 , … , p i } mex\{p_1,p_2,\dots,p_i\} mex{p1,p2,,pi} 的,所以直接倒退即可。

具体来说,我们知道了 m e x { p 1 , p 2 , … , p i } mex\{p_1,p_2,\dots,p_i\} mex{p1,p2,,pi},要去推 p i p_i pi,可以直接通过 a i a_i ai 算出 p i = m e x { p 1 , p 2 , … , p i } − a i p_i=mex\{p_1,p_2,\dots,p_i\}-a_i pi=mex{p1,p2,,pi}ai。然后去掉 p i p_i pi 算出 m e x { p 1 , p 2 , … , p i − 1 } mex\{p_1,p_2,\dots,p_{i-1}\} mex{p1,p2,,pi1} 就可以继续逆推了。

code1:

队友的代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pb push_back
#define endl '\n'
#define VI vector<int>
#define pii pair<int, int>
#define rep(i, j, k) for (int i = j; i <= k; ++i)
#define per(i, j, k) for (int i = j; i >= k; --i)
#define print(a) cout << a << endl;
#define NO return cout << "No\n", void()
#define YES return cout << "Yes\n", void()

const int inf = 0x3f3f3f3f;
const long long llinf = (long long)0x3f3f3f3f3f3f3f3f;
const long long MOD = (long long)1e9 + 7LL;
const size_t N = (size_t)1e6 + 5;

#define IO                       \
    ios::sync_with_stdio(false); \
    std::cin.tie(0);             \
    std::cout.tie(0)

#define debug(a) std::cerr << "\033[34m" << #a << ':' << a << "\033[0m" << endl

#define debugList(list)                        \
    std::cerr << "\033[34m" << #list << ": ["; \
    for (auto& e : list) {                     \
        std::cerr << e << ", ";                \
    }                                          \
    std::cerr << "\b\b]\033[0m" << endl

#define otto auto

int in() {
    int x;
    cin >> x;
    return x;
}

void solve(int cs) {
    int n = in();
    VI a(n + 1);
    int m = n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    VI ans;
    for (int i = n; i > 0; i--) {
        int t = m - a[i];
        ans.pb(t);
        m = min(m, m - a[i]);
    }
    reverse(ans.begin(), ans.end());
    for (auto i : ans) {
        cout << i << ' ';
    }
    cout << endl;
}   

signed main() {
    IO;
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    int T, TT = 1;
    T = 1; 
    cin >> T;
    while (T--) {
        solve(TT++);
    }
    return 0;
}

思路2(正推):

正推是比较难的,因为我们只知道 m e x { p 1 , p 2 , … , p i − 1 } mex\{p_1,p_2,\dots,p_{i-1}\} mex{p1,p2,,pi1},只能猜测 p i = m e x { p 1 , p 2 , … , p i − 1 } − a i p_i=mex\{p_1,p_2,\dots,p_{i-1}\}-a_i pi=mex{p1,p2,,pi1}ai ,不过有可能新加入的 p i = m e x { p 1 , p 2 , … , p i − 1 } p_i=mex\{p_1,p_2,\dots,p_{i-1}\} pi=mex{p1,p2,,pi1} m e x { p 1 , p 2 , … , p i } − a i mex\{p_1,p_2,\dots,p_{i}\}-a_i mex{p1,p2,,pi}ai 就会变化,就错了。

所以一种解决方案是:找到 p 1 , p 2 , … , p i − 1 p_1,p_2,\dots,p_{i-1} p1,p2,,pi1 中最小未出现的数 t t t(也就是mex值)。如果 t − a i t-a_i tai 得到的数不符合条件(<0,或者已经存在了),就加入 p i = t p_i=t pi=t,否则加入 t − a i t-a_i tai

为什么这么做是对的: p i p_i pi 要么等于其他没有出现的数,这时 p i = m e x { p 1 , p 2 , … , p i − 1 } − a i = t − a i p_i=mex\{p_1,p_2,\dots,p_{i-1}\}-a_i=t-a_i pi=mex{p1,p2,,pi1}ai=tai 就是对的( a i a_i ai 可能是负数),如果不对,那么变成 t t t m e x mex mex 发生变化就还有机会。因为题目保证一定有解,所以前者不成立,后者一定成立,验证前者成不成立就行了。

另外,两种情况一定不会同时成立,所以不会有二选一的情况出现。因为如果前者成立,那么 p i = t − a i p_i=t-a_i pi=tai 一定是没有出现过的数,一定 ≥ t \ge t t,因此 a i ≤ 0 a_i\le0 ai0。而后者成立则需要 m e x { p 1 , … , p i } − a i = t mex\{p_1,\dots,p_i\}-a_i=t mex{p1,,pi}ai=t,因为 m e x { p 1 , … , p i } > t mex\{p_1,\dots,p_i\}>t mex{p1,,pi}>t ,因此 a i > 0 a_i>0 ai>0。两种情况成立条件显然互斥。

时间复杂度方面,虽然用了 s e t set set 暴力求 m e x mex mex。因为随着数的加入, m e x mex mex 值是单调变大的,最后变成 n n n。我们可以不重置 t t t,让它从上一次的值继续向后找,这样找 n n n 次最后到达 n n n。时间复杂度就是 O ( n l o g n ) O(nlogn) O(nlogn) 了。

code2:

#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
const int maxn=2e5+5;

int T,n;
int a[maxn];

int main(){
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
set<int> S;
for(int i=1,t=0,x;i<=n;i++){
while(S.find(t)!=S.end())t++;//前i-1个数的mex 
if(t-a[i]<0 || S.find(t-a[i])!=S.end())x=t;
else x=t-a[i];
cout<<x<<" \n"[i==n];
S.insert(x);
}
}
return 0;
}

原文地址:https://blog.csdn.net/qq_45809243/article/details/137331731

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!