题解 | C++

雾之湖的冰精

https://ac.nowcoder.com/acm/contest/77231/A

A

签到题,没什么好说的

int a,b; cin>>a>>b;
cout<<(a+b<=9? "Yes":"No")<<endl;

B

排序+二分

ll n,x; cin>>n>>x;
vector<ll>aa(n);
for(auto &i:aa) cin>>i;
std::sort(aa.begin(),aa.end());
if(x<aa[0]){
  cout<<"0 "<<x<<endl; return 0;
}
int res=std::upper_bound(aa.begin(),aa.end(),x)-aa.begin();
cout<<res<<" "<<x-aa[res-1]<<endl;

C

比较有意思的一道题目。假设当前为,我们在其后面加一个数字,则+。因此我们只需要判断所有前缀为之间整数的最小495的倍数即可,这个范围很小,以至于我们可以直接暴力

不知道为什么牛客格式中加号'+'打不出来

ll n; cin>>n;
n%=495;
if(n==0){ cout<<"-1\n"; return 0; }

vector<int>dis(495);
int cnt=494, now=0;
while(cnt){
  now+=495;
  for(ll tt=now/10;tt;tt/=10){
    if(tt<495&&!dis[tt]){
      dis[tt]=now;
      --cnt;
    }
  }
}

auto res=std::to_string(dis[n]);
cout<<res.substr(std::to_string(n).size(),114514)<<endl;

D

博弈,思维。题目内容不够多,至少应该说一下什么是字典序才对。

先手为了达到最优,会把小的字母尽可能删去(如果不删去的话那么后手一定有办法让这个字母为首字母)。考虑到后手希望字典序尽量小,在第一个字母相同的情况下肯定只保留一个字母。

举例来说,我们不妨假设后手拿到字符串bbacd。显然此时后手最优一定是acd。那么先手为了不达到这个结果,一定会优先把那个a删去。其他情况同理。因此最后的结果一定是先手为了使字典序最优,直接自己把字符串删的只剩一位

int n; cin>>n;
std::string S; cin>>S;
cout<<std::max(S.front(),S.back())<<endl;

E

bfs,没有什么套路,就是注意bfs时一格一格地走(而不是走到不能走为止)

typedef long long ll;
typedef std::pair<int,int> PII;

PII operator+(PII x,PII y) {
    return {x.first+y.first,x.second+y.second};
}

vector<PII>dir={{1,0},{0,1},{-1,0},{0,-1}};

#define y first
#define x second
void solve()
{
    int n,m; cin>>n>>m;
    vector<std::string>mart(n);
    for(auto &i:mart) cin>>i;
    PII S,T;
    for(int i=0;i<n;++i) for(int j=0;j<m;++j){
        if(mart[i][j]=='S') S={i,j};
        else if(mart[i][j]=='T') T={i,j};
    }
    
    vector<vector<vector<int>>>vis(n,vector<vector<int>>(m,vector<int>(4,-1)));
    std::queue<std::pair<PII,int>>q;
    for(int i=0;i<4;++i){ q.emplace(S,i); vis[S.y][S.x][i]=0; }
    while(q.size()){
        auto [u,d]=q.front(); q.pop();
        if(u==T){ vis[T.y][T.x][0]=vis[T.y][T.x][d]; break; }
        if(mart[u.y][u.x]=='*'){
            for(int k=0;k<4;++k){
                vis[u.y][u.x][k]=vis[u.y][u.x][d];
                auto v=u+dir[k];
                if(v.y<0||v.x<0||v.y>=n||v.x>=m||~vis[v.y][v.x][k]) continue;
                if(mart[v.y][v.x]=='#') continue;
                vis[v.y][v.x][k]=vis[u.y][u.x][d]+1;
                q.emplace(v,k);
            }
        }
        else{
            auto v=u+dir[d];
            if(v.y<0||v.x<0||v.y>=n||v.x>=m||~vis[v.y][v.x][d]) continue;
            if(mart[v.y][v.x]=='#') continue;
            vis[v.y][v.x][d]=vis[u.y][u.x][d]+1;
            q.emplace(v,d);
        }
    }
    cout<<vis[T.y][T.x][0]<<endl;
}
#undef y
#undef x

F

状态压缩DP。对于 &运算到0 ,我们不是很好枚举,如果我们把原来所有的位数翻转,那么原问题相当于 |运算到所有位数为1,这是很好想的。我们只需要DP统计把所有位变成1所需的最少个数,那么n-dp[255]就是我们最终的答案

// 200,b = 11001000
// 255,b = 11111111
void solve()
{
    int n; cin>>n;
    int mask=(1<<8)-1, all=0;
    vector<int>aa(n), dp(256,1e9);
    for(auto &i:aa){
        cin>>i;
        i^=mask; all|=i;
        for(int sub=i;sub;sub=(sub-1)&i) dp[sub]=1;
    }
    if(all<mask){
        cout<<-1<<endl; return;
    }
    for(int i=1;i<256;++i){
        if(dp[i]==1) continue;
        for(int sub=i;sub;sub=(sub-1)&i) dp[i]=std::min(dp[i],dp[sub]+dp[i^sub]);
    }
    cout<<n-dp[255]<<endl;
}
全部评论

相关推荐

2 收藏 评论
分享
牛客网
牛客企业服务