ATcoder ABC 358 補題記錄(A~D,G)

yhbqwq發表於2024-06-15

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';
    }
}

相關文章