1. 程式人生 > 其它 >2021-TKK-ICPC Summer Training Camp Round #1 題解

2021-TKK-ICPC Summer Training Camp Round #1 題解

1:消滅星星

解析

最優策略是隻消滅一種顏色,最後一次性消滅另外一種顏色。據此策略,取兩種情況的最小值即可。

標程

    void solve(){
        int n,m;
        scanf("%d%d",&n,&m);
        int a0=0,a1=0;
        int f=-1;
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            if(f!=x){
                if(x==0){
                    a0++;
                    f=0;
                }
                else{
                    a1++;
                    f=1;
                }
            }
        }
        int res=min(a0,a1)+1;
        if(res<=m)printf("YES\n");
        else printf("NO\n");
    }

2: 下館子 -3

解析

答案是最後出勤次數最多,且出勤次數最先大於等於max次的同學。

考慮用map對字串做對映,最後算出最大值\(max\)。然後將出勤次數為\(max\)同學放入set集合。

重新遍歷一次,當出現出勤次數大於等於\(max\)​,判斷是否在set集合之中即可。

程式碼

#include<bits/stdc++.h>
#include<set>
#include<map>
typedef long long ll;
using namespace std;
pair<string,int>r[100005];
set<string>st;
map<string,int>mp;

//標程
void solve(){
    st.clear();
    mp.clear();
    int n ;
    scanf("%d",&n);
    int mx=INT_MIN;
    string res="null";
    for(int i=1;i<=n;i++){
        string s;
        int x;
        cin>>s>>x;
        r[i]={s,x};
        mp[s]+=x;
    }
    for(auto i:mp){
        mx=max(mx,i.second);
    }
    for(auto i:mp){
        if(i.second==mx){
            st.insert(i.first);
        }
    }
    mp.clear();
    for(int i=1;i<=n;i++){
        string name=r[i].first;
        int score=r[i].second;
        mp[name]+=score;
        if(mp[name]>=mx && st.count(name)){
            res=name;
            break;
        }
    }
    cout<<res;
}
int main() {
    solve();
    return 0;
}

3:光照強度-2

解析

根據資料量,考慮O(N)的dp解法。

  • 規定:\(r[i][j]\)​代表\([i,j]\)​的明亮度,\(g[i][j]\)​代表\([i,j]\)​處的燈泡亮度,\(g[i][j]=0\)​​代表此處沒有燈泡
  1. 假設方格\([i,j]\)​​沒有燈,且上下左右的方格的明亮度(燈和明亮度等價的)分別如圖所示。

此位置的明亮度由4個方向遞減而來。

  • 左邊:能貢獻\(2-1=1\)​的明亮度
  • 上邊:能貢獻\(4-1=3\)​的明亮度
  • 右邊:能貢獻\(3-1=2\)​​的明亮度
  • 下邊:能貢獻$5-1=4 $​​的明亮度

因此此處的明亮值為\(max(1,3,2,4)\)

​​

  1. 如果方格\([i,j]\)有一盞燈,\(g[x][y]=5\)

此處的明亮值為\(max(1,3,2,4,g[x][y])=5\)​​

因此我們可以推斷出狀態轉移方程。

\[r[i][j]=max(g[i][j],r[i+1][j],r[i][j+1],r[i-1][j],r[i][j-1],r[i][j]) \]

但是,如果只從左上角開始遍歷一次,第一次遍歷到某個點的時候,下方和右方沒有資料,因此要從4個方向維護每個位置​的最大值。

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
typedef pair<int,int>pii;
const int N =1005;
int r[N][N];
int g[N][N];
void solve(){
    int a,b,m;
    scanf("%d%d%d",&a,&b,&m);
    for(int i=1;i<=m;i++){
        int x,y,c;
        scanf("%d%d%d",&x,&y,&c);
        g[x][y]=max(g[x][y],c);
    }
    //左上角
    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            int q=r[i-1][j]-1,p=r[i][j-1]-1;
            int t=max(0,max(q,p));
            r[i][j]=max(max(g[i][j],t),r[i][j]);
        }
    }
    //右下角
    for(int i=a;i>=1;i--){
        for(int j=b;j>=1;j--){
            int q=r[i+1][j]-1,p=r[i][j+1]-1;
            int t=max(0,max(q,p));
            r[i][j]=max(max(g[i][j],t),r[i][j]);
        }
    }

    //右上角
    for(int i=1;i<=a;i++){
        for(int j=b;j>=1;j--){
            int q=r[i-1][j]-1,p=r[i][j+1]-1;
            int t=max(0,max(q,p));
            r[i][j]=max(max(g[i][j],t),r[i][j]);
        }
    }
    //左下角
    for(int i=a;i>=1;i--){
        for(int j=1;j<=b;j++){
            int q=r[i+1][j]-1,p=r[i][j-1]-1;
            int t=max(0,max(q,p));
            r[i][j]=max(max(g[i][j],t),r[i][j]);
        }
    }

    for(int i=1;i<=a;i++){
        for(int j=1;j<=b;j++){
            if(j!=1)printf(" ");
            printf("%d",r[i][j]);
        }
        printf("\n");
    }
}
int main() {
    solve();
    return 0;
}