牛客小白月赛88-DE题解

D-我不是大富翁

题意:

做法:一开始是往贪心方面想,但是很明显,贪不了。又因为走的步先后顺序没影响,可以用dp来写。暴力也差不多。

值得注意的点是动力序列可以一边读入一边处理,省了点空间。

如果dp[5005][5005]这样开的话会MLE,实际上在dp的过程中,用到的只是i和i-1两行,其余都是多余的。

所以可以这样定义dp[2][5005]这样可以避免MLE;

还有就是要特判n==1的情况。

//int dp[5005][5005];  //--MLE
int dp[2][5005];  //优化空间!!!                  wa--5 1 0
//dp[i][j]定义为,到了第i步,可以到达j哪些格子。
//暴力差不多--遍历m步.每步遍历n,看看可以到达哪些格子.看看最后一步是否可以到达1.

void solve(){           //D
    int n,m,x;
    cin>>n>>m;
    if(n==1){               //特判!!
        cout<<"YES";
        return;
    }
    dp[0][1]=1;
    for(int i=1;i<=m;i++){
        cin>>x;
        x%=n;
        for(int j=1;j<=n;j++){
            if(dp[(i+1)%2][j]){
                    dp[(i+1)%2][j]=0;      //重置!!!否则下一步会再次进入
                    dp[i%2][(j+x)%n]=1;
                    dp[i%2][(j-x+n)%n]=1;
            }
        }
    }
    if(dp[m%2][1]) cout<<"YES";
    else cout<<"NO";
}

在写的时候加了个条件判断x==0的情况,但是实际上x==0的情况是相同处理的,不用特别处理。

E-多重映射

题意:

做法有两种。

法一:顺着做,并查集(维护集合的关系,不是值的关系),加一点其他辅助。设置两个unordered_map<int,int>:mp1[集合]=值 ,mp2[值]=集合。

int fa[1000006];            //fa存的是各个集合,不是值!!
int find(int x){
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
void Union(int x,int y){
    int fa1=find(x),fa2=find(y);
    fa[fa1]=fa2;
}
//这题顺着做,映射关系有点绕,要想清楚映射关系!!
void solve(){       //E多重映射--①多重映射 or ②正难则反     有T=1e5组样例,ai最大又有1e6。如果每个样例都初始化到1e6--TLE--solve--输入哪个数字初始化哪个数字。
    int n,m,arr[100005];
    cin>>n>>m;
    map<int,int> mp1,mp2;    //key!! mp1[集合]=值 : mp2[值]=集合
    for(int i=1;i<=n;i++){
        cin>>arr[i];
        fa[arr[i]]=arr[i];
        mp1[arr[i]]=arr[i];
        mp2[arr[i]]=arr[i];
    }
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        if(!mp2[x]||x==y) continue;  //x不存在于集合
        if(!mp2[y]){                //如果y不存在于集合
            mp2[y]=mp2[x];          //y存在于x的集合
            mp1[mp2[x]]=y;          //x的集合对应的值为y
            mp2.erase(x);           //删除x,x不存在于集合
        }
        else{
            Union(mp2[x],mp2[y]);   //集合的Union!!
            //x集合已经融入到y集合,所以要先删除x集合对应的值,并且删除x集合。
            mp1.erase(mp2[x]);
            mp2.erase(x);
        }
    }
    for(int i=1;i<=n;i++) cout<<mp1[find(arr[i])]<<" ";
    cout<<endl;
}

法二:巧妙,正难则反。倒着遍历操作。

int fa[1000006];
void solve(){           //E-法二-正难则反
    int n,m,arr[100005];
    cin>>n>>m;
    for(int i=1;i<=n;i++) {
        cin>>arr[i];
        fa[arr[i]]=arr[i];   //!!!
    }
    vector<pair<int,int>> vct;
    for(int i=1;i<=m;i++){
        pair<int,int> x;
        cin>>x.first>>x.second;
        vct.emplace_back(x);
        fa[x.first]=x.first;            //!!!所有出现的数字都要初始化为自己
        fa[x.second]=x.second;
    }
    for(int i=m-1;i>=0;i--){
        auto [x,y]=vct[i];
        fa[x]=fa[y];                    //!!!!!!
    }
    for(int i=1;i<=n;i++){
        cout<<fa[arr[i]]<<" ";
    }
    cout<<endl;
}

 

posted @ 2024-03-13 01:04  osir  阅读(11)  评论(0编辑  收藏  举报