• 第十七届中国计量大学程序设计竞赛部分题解


    比赛链接:第十七届中国计量大学程序设计竞赛



    B - Broken Pad

    两种情况:

    • 原字符串从左往右翻转;
    • 先单击空白处,再从左往右翻转。

    结果取两者中次数较少的。

    #include <iostream>
    #include <string>
    #include <queue>
    using namespace std;
    #define io_speed_up ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    
    string a, b;
    int t, cnt1, cnt2, cnt, len;
    queue <int> q1, q2;
    
    int main() {
    	io_speed_up;
    	cin >> t;
    	while (t--) {
    		cin >> a >> b;
    		while (!q1.empty())	q1.pop();
    		while (!q2.empty())	q2.pop();
    		cnt1 = cnt = 0, len = a.length();
    		for (int i = 0; i < len; ++i) {
    			int t1 = a[i] - '0', t2 = b[i] - '0';
    			if (cnt && t1 ^ 1 != t2) {
    				q1.push(i + 1);
    				cnt ^= 1;
    				cnt1++;
    			} else if (!cnt && t1 != t2) {
    				q1.push(i + 1);
    				cnt ^= 1;
    				cnt1++;
    			}
    		}
    		cnt2 = 1, cnt = 0;
    		q2.push(0);
    		for (int i = 0; i < len; ++i) {
    			int t2 = b[i] - '0';
    			if (cnt && !t2) {
    				q2.push(i + 1);
    				cnt ^= 1;
    				cnt2++;
    			} else if (!cnt && t2) {
    				q2.push(i + 1);
    				cnt ^= 1;
    				cnt2++;
    			}
    		}
    		if (cnt1 <= cnt2) {
    			while (!q1.empty()) {
    				cout << q1.front() << ' ';
    				q1.pop();
    			}
    		} else {
    			while (!q2.empty()) {
    				cout << q2.front() << ' ';
    				q2.pop();	
    			}
    		}
    		cout << endl;
    	}
    	return 0;
    }
    

    C - Cook Steak

    一道简单的模拟题,按顺序计算时间即可。

    #include <iostream>
    #include <vector>
    using namespace std;
    #define ll long long
    
    int t, n;
    
    int main() {
        cin >> t;
        while (t--) {
            cin >> n;
            vector <pair<int, int> > vec;
            for (int i = 1; i <= n; ++i) {
                int l, r;
                cin >> l >> r;
                vec.push_back(make_pair(l, r));
            }
            int now = 0, p = 0;
            ll time = 0;
            while (p < n) {
                int v = 1;
                if (now < vec[p].first) {
                    v = vec[p].first - now;
                    now = vec[p].first;
                }
                else if (now > vec[p].second) {
                    v = now - vec[p].second;
                    now = vec[p].second;
                }
                else { 
                    p++; 
                }
                time += v;
            }
            cout << time << endl;
        }
        return 0;
    }
    

    D - Dessert Time

    首先我们将出现的数字排序,统计出现次数,这里选用map存储。
    可以分类成以下三种情况:

    1. 从大到小看,第一个出现奇数次的数是最小的数:
      如果我们第一步拿最小的数,那么之后对手只需要按顺序拿即可让我们拿最后一个数;如果我们第一步拿其他数,那么对手只需模仿我们的操作,直到拿掉最后一个数让我们兜底;因此,这是必败态;
    2. 从大到小看,第一个出现奇数次的数不是最小的数:
      此时我们只要第一步拿这个奇数次的数就是必胜,当我们拿了该数以后,它及它之后的数字全都是偶数次,我们只需要模仿对手的操作即可拿到最后一个数使对手兜底;
    3. 所有数都是偶数次:
      此时我们先手取最小的数必胜,若对手模仿我们的操作,他会拿到最后一个数,若他不模仿我们的操作而先拿一个较大的数,那么我们模仿他的操作,就能拿到最后一个数使对手兜底。
    #include <iostream>
    #include <map>
    using namespace std;
    
    int t, n, x, ans;
    map <int, int> mat;
    
    int main() {
    	cin >> t;
    	while (t--) {
    		mat.clear();
    		cin >> n;
    		for (int i = 1; i <= n; ++i) {
    			cin >> x;
    			mat[x]++;
    		}
    		ans = -1;
    		for (auto iter = (--mat.end()); ; --iter) {
    			if (iter->second & 1) {
    				ans = iter->first;
    				break;
    			}
    			if (iter == mat.begin()) {
    				break;
    			}
    		}
    		if (ans == -1) {
    			ans = mat.begin()->first;
    		} else if (ans == mat.begin()->first) {
    			ans = -1;
    		}
    		cout << ans << endl;
    	}
    	return 0;
    }
    

    E - Eat Grapes

    首先考虑一般情况:
    当一个节点连接大于1个葡萄时,先手的人总能通过策略留最后1个葡萄给对手,所以这题变成在求当遇到第一个拥有大于1个葡萄的节点时谁是先手;
    当一个节点没有连接葡萄时,它只拥有上一个节点这1个葡萄,所以我们只要知道最后连续有多少个节点没有连接葡萄,就可以知道之后谁先手;
    由于最后一个节点总留有一个额外的葡萄,所以偶数个连续的节点代表SYH赢。
    特殊情况:
    如果所有节点都没有连接葡萄,那么结果与上面的情况相反。

    #include <iostream>
    using namespace std;
    
    int t, n, num, cnt;
    
    int main() {
    	cin >> t;
    	while (t--) {
    		cin >> n;
    		cnt = 0;
    		for (int i = 1; i <= n; ++i) {
    			cin >> num;
    			if (num) {
    				cnt = 0;
    			} else {
    				cnt++;
    			}		
    		}
    		if (cnt == n) {
    			if (cnt % 2) {
    				cout << "these are sweet grapes" << endl;
    			} else {
    				cout << "these are sour grapes" << endl;
    			}
    		} else if (cnt % 2) {
    			cout << "these are sour grapes" << endl;
    		} else {
    			cout << "these are sweet grapes" << endl;
    		}
    	}
    	return 0;
    }
    

    F - Flag Scramble Competition

    签到题,数都能数出来。

    #include <cstdio>
    using namespace std;
     
    int main() {
        printf("e");
        return 0;
    }
    

    H - Happy Time is Always Short

    线段树的模板题,把求和改成取最大值即可。

    #include <cstring>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    #define ll long long
    #define ms(a, b) memset(a, b, sizeof(a))
    
    struct node {
    	ll tree, left, right, lazy;
    } a[400050];
    
    ll t, n, m, add, ans, x, y;
    
    ll read() {
    	char x = getchar(); ll ans = 0; int f = 1;
    	while (!isdigit(x)) {
    		if (x == '-')   f = -1;
    		x = getchar();
    	}
    	while (isdigit(x)) {
    		ans = (ans << 3) + (ans << 1) + (x ^ 48);
    		x = getchar();
    	}
    	return ans * f;
    }
    
    void create(ll l, ll r, ll k) {
    	a[k].lazy = 0, a[k].left = l, a[k].right = r;
    	if (l == r) {
    		a[k].tree = read();
    		return;
    	}
    	ll mid = l + r >> 1;
    	create(l, mid, k * 2);
    	create(mid + 1, r, k * 2 + 1);
    	a[k].tree = max(a[k * 2].tree, a[k * 2 + 1].tree);
    	return;
    }
    
    void load(ll k) {
    	ll l = k * 2, r = k * 2 + 1;
    	a[l].lazy = 1;
    	a[r].lazy = 1;
    	a[l].tree = 0;
    	a[r].tree = 0;
    	a[k].lazy = 0;
    	return;
    }
    
    void change(ll k) {
    	if (a[k].left >= x && a[k].right <= y) {
    		a[k].tree = 0;
    		a[k].lazy = 1;
    		return;
    	}
    	if (a[k].lazy)      load(k);
    	ll mid = a[k].left + a[k].right >> 1;
    	if (x <= mid)       change(k * 2);
    	if (y >= mid + 1)   change(k * 2 + 1);
    	a[k].tree = max(a[k * 2].tree, a[k * 2 + 1].tree);
    	return;
    }
    
    void inquery(ll k) {
    	if (a[k].left >= x && a[k].right <= y) {
    		ans = max(ans, a[k].tree);
    		return;
    	}
    	if (a[k].lazy)      load(k);
    	ll mid = a[k].left + a[k].right >> 1;
    	if (x <= mid)       inquery(k * 2);
    	if (y >= mid + 1)   inquery(k * 2 + 1);
    	return;
    }
    
    int main() {
    	t = read();
    	while (t--) {
    		ms(a, 0);
    		n = read();
    		m = read();
    		create(1, n, 1);
    		while (m--) {
    			x = read(), y = read();
    			ans = 0;
    			change(1);
    			x = 1, y = n;
    			inquery(1);
    			printf("%lld
    ", ans);
    		}
    	}
    	return 0;
    }
    

    I - Isolated Pointset

    根据说明就能看出来,只要大于等于三个点,就可以一直拼成一排等边三角形。

    #include <iostream>
    using namespace std;
    
    int t, num;
    
    int main() {
    	cin >> t;
    	while (t--) {
    		cin >> num;
    		if (num > 2) {
    			cout << "Yes" << endl;
    		} else {
    			cout << "No" << endl;
    		}
    	}
    	return 0;
    }
    

    J - Jiufeng's Football Team

    用种类并查集来区分两个团队,在球员之间建边,边权为训练时间。
    给定一个时间,大于该时间的边所属的两个球员放在不同团队;当所有球员都分配完毕时,没有出现矛盾的情况,则该时间满足条件;若出现两个球员的训练时间大于给定时间,但根据之前球员的分配,这两个球员在同一团队,则产生矛盾,该时间不满足条件。
    通过二分的方法来获取训练时间的最小值。

    #include <iostream>
    #include <vector>
    using namespace std;
    #define ll long long
    #define MAXN 400010
    
    int t, n, m, fa[MAXN], x, y, w;
    struct Edge {
    	int to, w;
    };
    vector <Edge> edge[MAXN];
    
    int find(int x) {
    	return x == fa[x] ? x : fa[x] = find(fa[x]);
    }
    
    bool check(int x) {
    	for (int i = 1; i <= 2 * n; ++i)	fa[i] = i;
    	for (int i = 1; i <= n; ++i) {
    		for (auto iter : edge[i]) {
    			if (iter.w <= x)	continue;
    			int nxt = iter.to;
    			int x = find(i);
    			int y = find(nxt);
    			if (x == y)	return false; // 在同一个团队
    			fa[find(x + n)] = find(y);
    			fa[find(y + n)] = find(x);
    		}
    	}
    	return true;
    }
    
    int main() {
    	cin >> t;
    	while (t--) {
    		cin >> n >> m;
    		for (int i = 1; i <= n; ++i)	edge[i].clear();
    		for (int i = 1; i <= m; ++i) {
    			cin >> x >> y >> w;
    			edge[x].push_back(Edge{y, w});
    			edge[y].push_back(Edge{x, w});
    		}
    		int l = 0, r = 1e9, ans = r;
    		while (l <= r) {
    			int mid = l + r >> 1;
    			if (check(mid)) {
    				r = mid - 1;
    				ans = mid;
    			} else {
    				l = mid + 1;
    			}
    		}
    		cout << ans << endl;
    	}
    	return 0;
    }
    

    K - Known-Well Palindrome Date-Easy Version

    按顺序从左往右判断:

    1. 先用string类的substr函数每次截取八个字符;
    2. 用algorithm头文件里的reverse函数翻转截取的字符串,并与原字符串判断回文;
    3. 判断八个字符中是否存在空格;
    4. 判断日期的合理性。
    #include <iostream>
    #include <string>
    #include <algorithm>
    using namespace std;
    
    int n, len;
    string s;
    
    bool judge(int year) {
        return (!(year % 400) || year % 100 && !(year % 4));
    }
    
    int main() {
        while (getline(cin, s)) {
            if (s == "#")   break;
            n = 0;
            len = s.length();
            for (int i = 0; i <= len - 8; ++i) {
                // 判断回文 
                string s1 = s.substr(i, 8);
                string s2 = s1;
                reverse(s1.begin(), s1.end());
                if (s1 == s2) {
                    // 去除空格 
                    bool flag = false;
                    for (int j = i; j <= i + 7; ++j) {
                        if (s[j] > '9' || s[j] < '0') {
                            flag = true;
                            break;  
                        }
                    }
                    if (flag)   continue;
                    // 判断日期合理性 
                    int yy = (((s[i] - '0') * 10 + s[i + 1] - '0') * 10 + s[i + 2] - '0') * 10 + s[i + 3] - '0';
                    int mm = (s[i + 4] - '0') * 10 + s[i + 5] - '0';
                    int dd = (s[i + 6] - '0') * 10 + s[i + 7] - '0';
                    if (mm == 1 || mm == 3 || mm == 5 || mm == 7 || mm == 8 || mm == 10 || mm == 12) {
                        if (dd <= 31 && dd > 0) {
                            n++;
                        }
                    } else if (mm == 4 || mm == 6 || mm == 9 || mm == 11) {
                        if (dd <= 30 && dd > 0) {
                            n++;
                        }
                    } else if (mm == 2) {
                        if (judge(yy)) {
                            if (dd <= 29 && dd > 0) {
                                n++;
                            }
                        } else {
                            if (dd <= 28 && dd > 0) {
                                n++;
                            }
                        }
                    }
                }
            }
            cout << n << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    研究SandHook
    MYSQL 事务与锁
    Java创造者詹姆斯·高斯林采访
    mybatis like 模糊查询
    【科普】彻底搞清楚什么是交换机什么是路由器。程序员基本功哦
    MinIO的简单使用实践
    如何将微信公众号的文章怎么保存转化为word文档?
    如何在recoil中主动刷新seloctor中缓存的值
    【译文】探索Recoil中的异步请求
    魅族云相册批量下载方案
  • 原文地址:https://www.cnblogs.com/IzumiSagiri/p/13736129.html
Copyright © 2020-2023  润新知