【牛客训练记录】第六届山东师范大学与齐鲁工业大学大学生程序设计联赛

训练情况

赛后反思

F题一血因为 QLU 技术原因被吃了,题目看太急了没看到有空格寄了一发,尽力局,除了动态规划DP那道C题,其他感觉还挺满意的,剩下可能就真不会了

C题

考虑动态规划,DP[i][0/1] 表示第 \(i\) 位涂成红/蓝色的答案,同色加上对应颜色答案贡献和额外的答案贡献,异色加上对应的颜色答案贡献,动态规划的转移方程如下

\[dp[i][0] = max(dp[i-1][0] + a[i] + c[i-1] + c[i],dp[i-1][1] + a[i]) \]

\[dp[i][1] = max(dp[i-1][1] + b[i] + c[i-1] + c[i],dp[i-1][0] + b[i]) \]

#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

void solve(){
    int n; cin>>n;
    vector<int> a(n + 1),b(n + 1),c(n + 1);
    for(int i = 1;i<=n;i++) cin>>a[i];
    for(int i = 1;i<=n;i++) cin>>b[i];
    for(int i = 1;i<=n;i++) cin>>c[i];
    vector<vector<int>> dp(n + 1,vector<int>(2));
    dp[1][0] = a[1];
    dp[1][1] = b[1];
    for(int i = 2;i<=n;i++){
        dp[i][0] = max(dp[i-1][0] + a[i] + c[i-1] + c[i],dp[i-1][1] + a[i]);
        dp[i][1] = max(dp[i-1][1] + b[i] + c[i-1] + c[i],dp[i-1][0] + b[i]);
    }
    cout<<max(dp[n][0],dp[n][1])<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

D题

求环的最短和最长长度,我们可以使用并查集(DSU)维护环的关系,最后计数每一个环的长度求 min 和 max 即可。

#include <bits/stdc++.h>
// #define int long long
#define endl '\n'

using namespace std;

const int N = 5007;

int n;
int a[N];
int fa[N];
int cnt[N];

int Find(int x){
    if(fa[x] == x) return x;
    return fa[x] = Find(fa[x]);
}

void Union(int x,int y){
    x = Find(x); y = Find(y);
    if(x == y) return;
    fa[y] = x;
}

void solve(){
    cin>>n;
    for(int i = 1;i<=n;i++) cin>>a[i],fa[i] = i;
    for(int i = 1;i<=n;i++){
        Union(i,a[i]);
    }
    for(int i = 1;i<=n;i++){
        cnt[Find(i)]++;
    }
    int ma = -N,mi = N;
    for(int i = 1;i<=N-7;i++){
        if(cnt[i] == 0) continue;
        ma = max(ma,cnt[i]);
        mi = min(mi,cnt[i]);
    }
    cout<<mi<<" "<<ma<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

F题

我的一血被吃了,这题有空格需要使用 getline(因为这个问题 WA 了一发),判断字符串中是否有 English

#include <bits/stdc++.h>
// #define int long long
#define endl '\n'

using namespace std;

void solve(){
    string s; getline(cin,s);
    int ans = 0;
    for(int i = 0;i<s.size()-6;i++){
        string ss = s.substr(i,7);
        if(ss == "English") ans++;
    }
    cout<<ans<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

I题

纯排序题,有点像 ICPC 2024 第二场网络赛的那道题,我们计算交换两个位置前后对答案的贡献,我们发现按照 \(\frac{t}{h}\) 从小到大排序才能让答案最小,一样的情况下取编号小的。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'

using namespace std;

const int N = 2e5 + 3;

int n;

struct node{
    int id,t,h;
}a[N];

bool cmp(node x,node y){
    if(x.h*y.t == y.h*x.t) return x.id < y.id;
    else return x.t*y.h < y.t*x.h;
}

void solve(){
    cin>>n;
    for(int i = 1;i<=n;i++){
        cin>>a[i].t>>a[i].h;
        a[i].id = i;
    }
    sort(a+1,a+1+n,cmp);
    for(int i = 1;i<=n;i++){
        cout<<a[i].id<<" ";
    }
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

J题

图论 Dijkstra 最短路模板,只需要在入优先队列之前判断一下这个节点是否崩坏,还没崩坏就入队即可。

#include <bits/stdc++.h>
// #define int long long
#define endl '\n'

using namespace std;

const int N = 1e5 + 3;

int n,m;
int t[N];
int head[N],tot;

struct node{
    int id,dis;
    bool operator <(const node &x)const{
        return dis > x.dis;
    }
};

struct edge{
    int u,v,w,nxt;
}edge[N<<1];

int dist[N];
bool vis[N];

priority_queue<node> q;

void dij(){
	memset(dist,0x3f3f3f3f,sizeof(dist));
	dist[1] = 0;
	q.push((node){1,0});
	while(q.size()){
		int x = q.top().id; q.pop();
		if(vis[x]) continue;
		vis[x] = 1;
		for(int i = head[x];i;i = edge[i].nxt){
			int v = edge[i].v;
			int w = edge[i].w;
			if(dist[v] > dist[x] + w && dist[x] + w < t[v]){
				dist[v] = dist[x] + w;
				q.push((node){v,dist[v]});
			}
		}
	}
}

void add_edge(int u,int v,int w){
    edge[++tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].nxt = head[u];
    head[u] = tot;
}

void solve(){
    cin>>n>>m;
    for(int i = 1;i<=n;i++) cin>>t[i];
    for(int i = 1;i<=m;i++){
        int u,v,w; cin>>u>>v>>w;
        add_edge(u,v,w);
        add_edge(v,u,w);
    }
    dij();
    if(dist[n] == 0x3f3f3f3f) cout<<"NO"<<endl;
    else cout<<"YES"<<endl<<dist[n]<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

L题

由题目可知一个人能喝 \(\frac{1}{3}\) 桶水,所以我们只要判断 \(x \times y\) 是否是 \(3\) 的倍数,如果是输出 \(\frac{xy}{3}\),否则输出 xiaoshu

#include <bits/stdc++.h>
// #define int long long
#define endl '\n'

using namespace std;

void solve(){
    int x,y; cin>>x>>y;
    if((x*y)%3==0) cout<<x*y/3<<endl;
    else cout<<"xiaoshu"<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}

M题

这题我们观察到数据范围很小,可以暴力枚举每一位放不放置障碍物,最后再BFS判断是否能走到终点即可。

#include <bits/stdc++.h>
// #define int long long
#define endl '\n'

using namespace std;

int n;
string s[5];
string a[5];
int cho[70];
int ans = INT_MAX;

int u[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};

int bfs(){
    queue<pair<int,int>> q;
    bool vis[70][70];
    int stx,sty,edx,edy;
    for(int i = 0;i<n;i++){
        for(int j = 0;j<n;j++){
            vis[i][j] = false;
            if(a[i][j] == 's') stx = i,sty = j;
            if(a[i][j] == 't') edx = i,edy = j;
        }
    }
    for(int i = 0;i<n*n;i++){
        if(cho[i]){
            int nowx = i/n;
            int nowy = i%n;
            if(nowx == stx && nowy == sty) continue;
            if(nowx == edx && nowy == edy) continue;
            a[nowx][nowy] = 'x';
        }
    }
    bool flag = false;
    q.push(make_pair(stx,sty));
    while(q.size()){
        int x = q.front().first;
        int y = q.front().second;
        if(x == edx && y == edy) flag = true;
        q.pop();
        for(int i = 0;i<4;i++){
            int xx = x + u[i][0];
            int yy = y + u[i][1];
            if(xx < 0 || xx >= n || yy < 0 || yy >= n || a[xx][yy] == 'x' || vis[xx][yy]) continue;
            vis[xx][yy] = 1;
            q.push(make_pair(xx,yy));
        }
    }
    int nowans = 0;
    for(int i = 0;i<n*n;i++) if(cho[i]) nowans++;
    if(!flag) return nowans;
    else return INT_MAX;
} 

void pd(){
    for(int i = 0;i<n;i++) a[i] = s[i];
    int nowans = bfs();
    if(nowans < ans) ans = nowans;
}

void dfs(int x){
    if(x == n*n){
        pd();
        return;
    }
    for(int i = 0;i<=1;i++){
        cho[x] = i;
        dfs(x + 1);
        cho[x] = 0;
    }
}

void solve(){
    cin>>n;
    for(int i = 0;i<n;i++) cin>>s[i];
    dfs(0);
    cout<<ans<<endl;
}

signed main(){
    // int T; cin>>T; while(T--)
    solve();
    return 0;
}
posted @ 2024-12-08 14:30  MNNUACM_2024ZY  阅读(39)  评论(0)    收藏  举报