当前位置: 首页 > news >正文

SMU Winter 2025 div1 3rd

文章目录

  • The Third Week
  • 一、前言
  • 二、算法
    • 1.深度优先搜索
      • <1>(Li Hua and Tree)
      • <2>(2025寒假训练4 L3-2)
    • 2.DP
      • <1>(牛客训练营6 B)
    • 3. 构造
      • <1>(Skibidus and Rizz)
      • <2>(Maximum Diameter Graph)
    • 4.并查集
      • <1>(2025暑假训练5 L2-2)
    • 5.广度优先搜索
      • <1>(公平对局)
  • 三、总结


The Third Week

人生到处知何似,应似飞鸿踏雪泥。 ————苏轼

一、前言

  • 2.09 牛客周赛 (2h) 4/5
  • 2.09 CFdiv4(2h)5/6
  • 2.10 CF训练赛 (2h)3/4
  • 2.11 牛客训练营 (5h) 5/6
  • 2.11 CFdiv2 (2h) 1/
  • 2.12 CF训练赛 (2h) 3/4
  • 2.13 PTA (3h) 228/232
  • 2.14 CF训练赛(2h)3/3
  • 2.15 PTA(3h)199/206

rating:

  • codeforces: 1339 —— 1294
  • 牛客:1543 —— 1532

二、算法

1.深度优先搜索

<1>(Li Hua and Tree)

题解:
李华有一颗有n个顶点和n-1条边的树,树的根是顶点1,每个顶点有重要性,子树的大小指其中顶点的数量,子树的重要性是其中顶点的重要性之和。非叶子顶点的重儿子是指拥有最大子树大小的儿子。如果存在多个,则重儿子是索引最小的那个。
用dfs搜索最远的叶子节点,对每一个叶子节点计算它的子树的大小和重要性即可,注意此处的dfs必须用俩个变量进行遍历。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
#define PII pair<int,int>

const int N = 1e6+10;
vector<int>c[N];
int fa[N],so[N];
int re[N]; //子树大小
int le[N];//重要性大小
set<PII>e[N];
int n,m;
int a[N];

void dfs(int x,int f) {
//    fa[x] = f;
//    if(c[x].size() == 1) {
//        re[x] = 1;
//        le[x] = a[x];
//        return ;
//    }
//    for (auto ma:c[x]) {
//        if(f == ma) continue;
//        dfs(ma,x);
//        re[x] += re[ma];
//        le[x] += le[ma];
//        e[x].insert({0-re[ma],ma});
//    }le[x] += a[x];
//    re[x] += 1;
      le[x] = a[x]; re[x] = 1; fa[x] = f;
      for (auto ma: c[x]) {
          if(f == ma) continue;
          dfs(ma,x);
          re[x] += re[ma];
          le[x] += le[ma];
          e[x].insert({-re[ma],ma});
      }
}

bool cmp(int p,int q) {
    if(re[p] == re[q]) return p < q;
    return re[p] > re[q];
}

void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i < n; i++) {
        int u,v;
        cin >> u >> v;
        c[u].push_back(v);
        c[v].push_back(u);
    }dfs(1,-1);

//    for (int i = 1; i <= n; i++) {
//        cout << le[i] << ' ' << re[i] << endl;
//    }

//     for (int i = 1; i <= n; i++) cout << fa[i] << ' ';

//    for (int i = 1; i <= n; i++) {
//        sort(c[i].begin(),c[i].end(),cmp);
//        c[i].erase(c[i].begin());
//    }

    while(m--) {
        int x; cin >> x;
        int y; cin >> y;
        if(x == 1) {
          //  cout << le[y] << endl;
          cout << le[y] << endl;
//          for (int i = 1; i <= n; i++) {
//              cout << le[i] << ' ';
//          }cout << endl;
        }
        else {
            if(e[y].empty()) continue;

            int zs = e[y].begin()->second;
            e[fa[y]].erase({-re[y],y});
            e[y].erase({-re[zs],zs});

  //          if(c[y].size() == 0) continue;
        //    sort(c[y].begin(),c[y].end(),cmp);
    //        c[y].erase(c[y].begin());

//            int ly = re[y],lx = le[y];
            re[y] -= re[zs];
            le[y] -= le[zs];
            re[zs] += re[y];
           le[zs] += le[y];
   //         c[zs].push_back(y);
   //         sort(c[zs].begin(),c[zs].end(),cmp);

            e[zs].insert({-re[y],y});
            e[fa[y]].insert({-re[zs],zs});
            fa[zs] = fa[y];
            fa[y] = zs;
        }
    }
//    return ;
}

signed main() {
    int t = 1;
 //   cin >> t;
    while(t--) solve();
}

<2>(2025寒假训练4 L3-2)

题解:
给出一行n个折角点的高度,然后给出m张碎纸,每张的第一个数字k表示碎纸的折角点,其后k个数字代表折角点的高度。给出m张碎纸的正确拼接顺序。
这题的数据量比较小,dfs当前位置有几个能放的碎纸,最后输出答案即可。
代码:

#include<bits/stdc++.h>
using namespace std;

#define int long long

int n,m;
vector<int> vs;
vector<int> vt;
vector<int> v[105];
vector<int> ans;


bool note[105];

void dfs(int now){
    if(ans.size() == m){
        vt = ans;
        return;
    }
    int i,j;
    for(i = 1;i <= m;++i){
        if(!note[i]){
            for(j = 0;j < v[i].size();++j){
                if(v[i][j] != vs[now + j])
                    break;
            }
            if(j == v[i].size()){
                ans.push_back(i);
                note[i] = true;
                dfs(now + j - 1);
                note[i] = false;
                ans.pop_back();
            }
        }
    }
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    int p,q;
    for(int i = 1;i <= n;++i){
        cin>>p;
        vs.push_back(p);
    }
    cin>>m;
    for(int i = 1;i <= m;++i){
        cin>>p;
        for(int j = 1;j <= p;++j){
            cin>>q;
            v[i].push_back(q);
        }
    }
    dfs(0);
    cout<<vt[0];
    for(int i = 1;i < vt.size();++i)
        cout<<" "<<vt[i];
    return 0;
}

给出一段26分的代码,用的是字符串匹配的思想,比较简洁,错误情况是俩个字符串都可以匹配到同一位置,无法确定是谁先匹配。如下。

#include<bits/stdc++.h>

using namespace std;
#define int long long

const int N = 1e5+10;
vector<int>a[110];
int h[N];
int n,m;
vector<pair<int,int>>mp;

signed main() {
    cin >> n;
    string s;
    cin >> s;
    getline(cin,s);
   // cout << s << endl;
    cin >> m;
    string y; getline(cin,y);
    for (int i = 1; i <= m; i++) {
        int x; cin >> x;
        getline(cin,y);
        int wz = s.find(y);
        mp.push_back({wz,i});
    }sort(mp.begin(),mp.end());
    int p = 0;
    for (auto x: mp) {
        p++;
        if(p == m) cout << x.second;
        else cout << x.second << ' ';
    }
}

2.DP

<1>(牛客训练营6 B)

题解:
在这里插入图片描述

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int N = 2e5 + 10;

void solve() {
	int n,c1,c2;cin>>n>>c1>>c2;
	vector<int> a(n+10),b(n+10);
	for(int i=1;i<=n;i++){
		cin>>a[i]>>b[i];
	}
	vector<vector<int>> dp(n+10,vector<int>(2,1e18));
	dp[0][0]=0;
	int ans=1e18;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=i-1;j++){
			//ai,bi接到aj,bj 
			if(a[i]>=a[j]&&b[i]>=b[j]){
				dp[i][0]=min(dp[i][0],dp[j][0]+c1*(i-j-1));
			}
			//ai,bi接到bj,aj
			if(a[i]>=b[j]&&b[i]>=a[j]){
				dp[i][0]=min(dp[i][0],dp[j][1]+c1*(i-j-1));
			} 
			//bi,ai接到aj,bj
			if(b[i]>=a[j]&&a[i]>=b[j]){
				dp[i][1]=min(dp[i][1],dp[j][0]+c2+c1*(i-j-1));
			} 
			//bi,ai接到bj,aj
			if(b[i]>=b[j]&&a[i]>=a[j]){
				dp[i][1]=min(dp[i][1],dp[j][1]+c2+c1*(i-j-1));
			} 
		}
		ans=min(ans,min(dp[i][0],dp[i][1])+c1*(n-i));
	}
	cout<<ans<<endl;
}

signed main() {
	std::ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int t = 1;cin >> t;
	while (t--) solve();
	return 0;
}

3. 构造

<1>(Skibidus and Rizz)

题解:
给定一个二进制字符串t,x表示0的个数,y表示1的个数,平衡值定义为01个数差值,给定n,m,k,要求构造包含n个0和m个1的二进字符串s使得所有子字符串中的最大平衡值恰好为k。如果不可能,输出-1.
假设n大于m,k n都输出-1,输出k个0,然后交替输出01,输出剩余的1。
代码:

#include <bits/stdc++.h>
using namespace std;

int main(){
	int t; cin >> t;
	while(t--){
		int n, m, k; cin >> n >> m >> k;
		if(max(n, m) - min(n, m) > k || k > max(n, m)){
			cout << "-1" << endl;
			continue;
		}
		else{
			pair<int, int> use1 = {n, 0}, use2 = {m, 1};
			if(m > n) swap(use1, use2);
			for(int i = 0; i < k; i++){
				cout << use1.second;
				use1.first--;
			}
			while(use2.first > 0){
				cout << use2.second;
				use2.first--;
				swap(use1, use2);
			}
			while(use1.first > 0){
				cout << use1.second;
				use1.first--;
			}
			cout << "\n";
		}
	}
}

<2>(Maximum Diameter Graph)

题解:
在这里插入图片描述

代码:

4.并查集

<1>(2025暑假训练5 L2-2)

冰岛人 20/25

题解:
用map实现题目要求,要注意calc部分判断五代以内公共祖先,必须找到公共祖先或者找到顶判断,各找五个是行不通的,不应该错。
代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long

const int N = 1e5+10;
int n,m;
map<string,string>fa;
map<string,int>ma;

bool calc(string x,string y) {
    int i = 1;
    for (string X = x; X != "ABCD"; X = fa[X],i++) {
        int j = 1;
        for (string Y = y; Y != "ABCD"; Y = fa[Y],j++) {
                    if(i>=5&&j>=5)
                return 1;
            if(X==Y&&(i<5||j<5))
                return 0;
        }
    }return 1;
}

void solve() {
    cin >> n;int p = 0;
    for (int i = 1; i <= n; i++) {
        string s1,s2; cin >> s1 >> s2;
        int q = s2.length()-1;
        if(s2[q] == 'n') {
            string ls;
            for (int j = 0; j <= q-4; j++) {
                ls += s2[j];
            }fa[s1] = ls;
            ma[s1] = 1;
        }else if(s2[q] == 'r') {
            string ls;
            for (int j = 0; j <= q-7; j++) {
                ls += s2[j];
            }fa[s1] = ls; 
            ma[s1] = 2;
        }
        else {
            fa[s1] = "ABCD";
            p++;
            if(s2[q] == 'm') ma[s1] = 1;
            else ma[s1] = 2;
        }
    }cin >> m;
    while(m--) {
        string m1,x1,m2,x2;
        cin >> m1 >> x1 >> m2 >> x2;
        if(fa[m1] == "" || fa[m2] == "") {
            cout << "NA" << endl;
            continue;
        }
        if(fa[m1] != "ABCD" && fa[m1] != x1) {
            cout << "NA" << endl;
            continue;
        }
        if(fa[m2] != "ABCD" && fa[m2] != x2) {
            cout << "NA" << endl;
            continue;
        }
            if(ma[m1] == ma[m2]) {
            cout << "Whatever" << endl;
        }else {
                if(calc(m1,m2)) cout << "Yes" << endl;
                else cout << "No" << endl;
        }
        
    }
    //cout << "PTA shi3 wo3 jing1 shen2 huan4 fa1 !" ;
}

signed main() {
    int t = 1;
    //cin >> t;
    while(t--) solve();
}

5.广度优先搜索

<1>(公平对局)

题解:
在这里插入图片描述
查找只差一颗就形成最大白色连通块里最大的连通块。考察bfs的运用

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e3+1,mod=1e9+7,INF=0x3f3f3f3f;

ll n,ans;
ll vis[N][N],value[N][N];
pair<ll,ll> dire[]={{0,1},{0,-1},{1,0},{-1,0}};
vector<string> mp(N);

bool limit(ll x,ll y){
    return (x>0&&x<=n&&y>0&&y<=n);
}

inline array<ll,3> bfs(vector<string> v,ll x,ll y){
    queue<pair<ll,ll>> q;
    vis[x][y]=1;
    q.push({x,y});
    ll cnt=0;
    set<pair<ll,ll>> blk;
    while(q.size()){
        auto [tx,ty]=q.front();
        q.pop();
        cnt++;
        for(auto d:dire){
            ll xx=tx+d.first,yy=ty+d.second;
            if(limit(xx,yy)){
                if(mp[xx][yy]=='*'&&!vis[xx][yy])
                    vis[xx][yy]=1,
                    q.push({xx,yy});
                else if(mp[xx][yy]=='.')
                    blk.insert({xx,yy});
            }
        }
    }
    if(blk.size()==1){
        pair<ll,ll> p=*blk.begin();
        return {p.first,p.second,cnt};
    }
    else 
        return {-1,-1,-1};
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n;
    for(ll i=1;i<=n;i++)
        cin>>mp[i],
        mp[i]=" "+mp[i];
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=n;j++)
            if(!vis[i][j]&&mp[i][j]=='*'){
                auto [x,y,z]=bfs(mp,i,j);
                if(x<0)continue;
                value[x][y]+=z;
                ans=max(ans,value[x][y]);
            }
    cout<<ans<<endl;
}


三、总结

状态还可以,会做的基本都可以做出来,做题速度不够快,补题不太及时。
比较偏算法的题目都比较生疏了,倒是思维题简单题目前都做得不错,PTA现阶段做得也还可以,加油。
CF和牛客都掉分了,虽然不多但是也不应该,有俩场打的不是很好。补题补题

相关文章:

  • JavaScript严格模式
  • NCHAR_CS和CHAR_CS,导致UNION ALL 时,提示SQL 错误 [12704] [72000]: ORA-12704: 字符集不匹配
  • Python参数的默认值进阶250216
  • Linux系统Centos安装部署nginx代理
  • win10 系统 自定义Ollama安装路径
  • 从安装软件到flask框架搭建可视化大屏(二)——创建一个flask页面,搭建可视化大屏,零基础也可以学会
  • Pointnet++改进75:添加PSConv模块 | 新型的风车状卷积
  • 频率自适应扩张卷积(FADC)详解及代码复现
  • 保持角色一致性的绘本生成AI开源项目之Story-Adapter本地部署Windows篇
  • 第三章:组件开发实战 - 第一节 - Tailwind CSS 常用UI组件构建
  • 【第15章:量子深度学习与未来趋势—15.3 量子深度学习在图像处理、自然语言处理等领域的应用潜力分析】
  • 数据结构与算法学习笔记----数位统计DP
  • 阅读论文“用于车联网安全车载通信的机器学习技术“的学习笔记
  • 进程令牌:Windows 安全架构中的关键元素
  • 在SpringBoot中使用UniHttp简化天地图路径规划调用实践
  • 【基于SprintBoot+Mybatis+Mysql】电脑商城项目之设置默认收货地址及删除收货地址
  • 【Qt Qml】QML与C++交互
  • 跟着AI学习vue3第一章
  • 文档格式转换引擎开发:支持PDF与OFD的技术实现
  • LeetCode 热门100题-最大子数组和-错题
  • 柬埔寨果农:期待柬埔寨榴莲走进中国市场
  • 80后女博士黄双燕拟提名为内蒙古盟市政府(行署)副职人选
  • 习近平就乌拉圭前总统穆希卡逝世向乌拉圭总统奥尔西致唁电
  • 董军同德国国防部长举行会谈
  • 万科再获深铁集团借款,今年已累计获股东借款近120亿元
  • 著名植物学家、园艺学家,国际植物园协会原主席贺善安逝世