ATcoder ABC 358 补题记录(A~D,G)

A

直接模拟即可。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100,mod=998244353;
int a[N];
signed main(){
    string s,t;
    cin>>s>>t;
    if(s=="AtCoder"&&t=="Land")cout<<"Yes\n";
    else cout<<"No\n";
}

B

直接模拟即可。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100,mod=998244353;
int a[N];
signed main(){
    int n,t;
    cin>>n>>t;
    for(int i=1;i<=n;i++)cin>>a[i];
    int now=-1e18;
    for(int i=1;i<=n;i++){
        int xu=now;
        if(xu<=a[i])now=a[i]+t;
        else now=xu+t;
        cout<<now<<'\n';
    }
}

C

发现 \(n\) 很小,所以直接暴力枚举每一个状态,并判断这个状态是否可以覆盖所有的爆米花。如果可以覆盖那么当前状态的位数就是当前所用的摊位的数量。取最小值即可。

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100,mod=998244353;
char s[3010][3010];
signed main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++)scanf("%s",s[i]);
    int cost=233;
    for(int i=1;i<(1ll<<n);i++){
        set<int>se;
        for(int j=0;j<n;j++)if(i>>j&1)
        for(int k=0;k<m;k++)if(s[j][k]=='o')
        se.insert(k);
        if(se.size()==m)cost=min(cost,(int)__builtin_popcountll(i));
    }
    cout<<cost<<'\n';
}

D

对于每一个人 \(i\),使用 multiset 找到让她可以满足的,价值最小的礼物分配给她。时间复杂度为 \(O(n\log n)\)

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100,mod=998244353;
int a[N],b[N];
signed main(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=m;i++)cin>>b[i];
    multiset<int>se;
    int res=0;
    for(int i=1;i<=n;i++)se.insert(a[i]);
    sort(a+1,a+n+1,greater<>());
    for(int i=1;i<=m;i++){
        auto it=se.lower_bound(b[i]);
        // cout<<"dbg "<<i<<' '<<b[i]<<'\n';
        if(it==se.end()){
            res=-1;
            break;
        }
        res+=*it;
        se.erase(it);
    }
    cout<<res<<'\n';
}

G

实际上 CF57E 也有一个(有点)类似的结论。

容易发现 \(n\times m\) 步之后一定可以到达任意的一个结点。因此 \(n\times m\) 步之后一定是停在某一个结点攒贡献。所以设 \(f_{i,j,k}\) 表示当前走了 \(i\) 步,目前位于结点 \((j,k)\) 的最大收益。很显然每一个 \(f_{i,j,k}\) 都可以从 \((j,k)\) 结点本身和 \((j,k)\) 结点四连通的结点转移而来。

此时若 \(k\le n\times m\) 则答案已经求出,\(k>n\times m\) 则枚举最后到达的每一个结点 \((i,j)\),这个结点的最大贡献就是 \(f_{n\times m,i,j}+(n\times m-k)\times a_{i,j}\)。可能这个贡献并不一定是最大贡献,但是最大贡献一定可以通过这种方式得到。

时间复杂度为 \(O(n^2m^2)\)

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000100,mod=998244353;
int a[55][55],f[55*55][55][55];
//设f[i][j][k]表示现在是第i个操作, 当前位于(j,k)
signed main(){
    int n,m,k;
    cin>>n>>m>>k;
    int si,sj;
    cin>>si>>sj;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    cin>>a[i][j];
    memset(f,-0x3f,sizeof f);
    f[0][si][sj]=0;
    for(int i=1;i<=min(n*m,k);i++){
    for(int j=1;j<=n;j++)
        for(int k=1;k<=m;k++)
            f[i][j][k]=f[i-1][j][k]+a[j][k];
    for(int j=1;j<=n;j++)
        for(int k=1;k<=m;k++){
            const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
            for(int d=0;d<4;d++){
                int x=j+dx[d],y=k+dy[d];
                if(x>=1&&x<=n&&y>=1&&y<=m)
                    f[i][x][y]=max(f[i][x][y],f[i-1][j][k]+a[x][y]);
            }
        }
    }
    if(k<=n*m){
        int res=0;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        res=max(res,f[k][i][j]);
        cout<<res<<'\n';
    }else{
        int res=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                int now=f[n*m][i][j]+(k-n*m)*a[i][j];
                res=max(res,now);
            }
        cout<<res<<'\n';
    }
}
posted @ 2024-06-15 22:15  yhbqwq  阅读(50)  评论(0编辑  收藏  举报