problem setter:
AaronWu
BrineTw
IvanLo
Repkironca
Aaw will never find that
名次
如果這場比賽有penalty你一定吃爆
kyle._.
如果這場比賽有penalty你一定賺爆
每發必中誒超強
kittyyyyyy
姆巴不配
其實就是計算己方球員跟敵方球員
相對於底線的距離,
如果己方球員離底線較近則輸出Yes
反之則輸出No
#include <iostream>
int main(){
int x, y;
while(std::cin >> x >> y){
x < y ? std::cout << "Yes\n" : std::cout << "No\n";
}
return 0;
}
AC扣
這題的定位是一題水題
# PRESENTING CODE
# AC code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
signed main() {
ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n;
cin >> n;
vector<int> arr(n);
for (auto &i : arr) cin >> i;
sort(arr.begin(), arr.end());
ll ans = 0;
for (int i = 0; i < n/2; ++i) {
ans += arr[i];
}
cout << ans << "\n";
}
# TLE code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n, temp;
cin >> n;
priority_queue<ll, vector<ll>, greater<ll> > s;
for(int i=0; i<n; i++){
cin >> temp;
s.push(temp);
}
ll sum =0;
for (int i = 0; i < n/2; i++){
sum += s.top();
s.pop();
}
cout << sum;
}
這樣寫沒有很好,但好多人這樣寫w
有人寫我的題目,好開心
#include <bits/stdc++.h>
using namespace std;
void dfs(int u, vector< vector<int> >& graph, vector<bool>& visited) {
visited[u] = 1;
for (auto& v: graph[u]) {
if (visited[v]) continue;
dfs(v, graph, visited);
}
}
int main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
vector< vector<int> > graph(n);
int u, v;
for (int i = 0; i < m; i++) {
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
vector<bool> visited(n);
dfs(0, graph, visited);
bool flag = 1;
for (int i = 0; i < n && flag; i++) {
flag = visited[i];
}
int q;
cin >> q;
for (int i = 0; i < q; i++) {
cout << (flag ? "No\n" : "Yes\n");
}
}
#include <bits/stdc++.h>
using namespace std;
vector< vector<int> > graph;
vector<bool> visited;
void dfs(int u) {
visited[u] = 1;
for (auto& v: graph[u]) {
if (visited[v]) continue;
dfs(v, graph, visited);
}
}
int main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
graph.resize(n);
int u, v;
for (int i = 0; i < m; i++) {
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
visited.resize(n);
dfs(0);
bool flag = 1;
for (int i = 0; i < n && flag; i++) {
flag = visited[i];
}
int q;
cin >> q;
for (int i = 0; i < q; i++) {
cout << (flag ? "No\n" : "Yes\n");
}
}
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
vector< vector<int> > graph(n);
int u, v;
for (int i = 0; i < m; i++) {
cin >> u >> v;
graph[u].push_back(v);
graph[v].push_back(u);
}
vector<bool> visited(n);
function<void(int)> dfs = [&](int u) {
visited[u] = 1;
for (auto& v: graph[u]) {
if (!visited[v]) dfs(v);
}
};
dfs(0);
bool flag = 1;
for (int i = 0; i < n && flag; i++) {
flag = visited[i];
}
int q;
cin >> q;
for (int i = 0; i < q; i++) {
cout << (flag ? "No\n" : "Yes\n");
}
}
MR 的假解
(竟然差點沒有卡掉)
這題就只是一題背包問題啦
# PRESENTING CODE
總共n個物品,每個都有特定價值\(v_i\),而搶救他需花費\(t_i\)的時間,總共不能花超過\(m\)的時間
可以發覺所謂的時間,其實就對應原本背包問題的重量!
但是...魔鬼藏在細節裡...
# PRESENTING CODE
先看到subtask 1,我們可以發覺我並沒有保證 \(t_i < m\)
也就是說,原本簡報上的那個做法
其實會有問題
# PRESENTING CODE
for(int i = 1; i <= n; ++i) {
int w, p;
cin >> w >> p; // 輸入重量、價值
for(int j = 0; j < w; ++j) {
dp[i][j] = dp[i-1][j]; //放不下所以只能選擇不放
}
for(int j = w; j <= m; ++j) { // 記得從w開始
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w] + p);
}
}
我們可以看到,第4行的迴圈,如果 w 大於 m
這時候你的dp陣列又只有剛好開到m的話,
你就會吃 RE
(或是RE有可能會顯示成WA或TLE)
這份程式碼只有在保證 \(w < m\) 時才是對的
# PRESENTING CODE
for(int i = 1; i <= n; ++i) {
int w, p;
cin >> w >> p; // 輸入重量、價值
for(int j = 0; j < w; ++j) {
dp[i][j] = dp[i-1][j]; //放不下所以只能選擇不放
}
for(int j = w; j <= m; ++j) { // 記得從w開始
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w] + p);
}
}
不過因為我抄學長簡報
所以我原本沒注意到這個錯w
所以賽中有人改開全域變數就過的原因是因為陣列一開始就夠大所以不會 index out of bound
# PRESENTING CODE
for(int i = 1; i <= n; ++i) {
int w, p;
cin >> w >> p; // 輸入重量、價值
for(int j = 0; j < m; ++j) {
if (j < w) {
dp[i][j] = dp[i-1][j]; //放不下所以只能選擇不放
}
else {
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w] + p);
}
}
}
# PRESENTING CODE
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define endl '\n'
#define AI(x) begin(x),end(x)
#define _ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
signed main(){_
int n, m;
cin >> n >> m;
vector<ll> v(n+1);
vector<ll> w(n+1);
for (int i = 1; i <= n; ++i) cin >> v[i];
for (int i = 1; i <= n; ++i) cin >> w[i];
ll vsum = 0;
for (auto &i : v) vsum+=i;
vector< vector<ll> > dp(n+1, vector<ll>(m+1, 0));
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
if (j < w[i]) {
dp[i][j] = dp[i-1][j];
}else{
dp[i][j] = max(dp[i-1][j - w[i]] + v[i], dp[i-1][j]);
}
}
}
cout << vsum - dp[n][m] << endl;
return 0;
}
不過你會發覺這一份程式碼沒辦法讓你AC
# PRESENTING CODE
你會發覺,subtask 2 的dp陣列
你開滿一定會吃 MLE
就算你用 vector 也一樣
所以 ...
要用滾動 dp !!!
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define endl '\n'
#define AI(x) begin(x),end(x)
#define _ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
signed main(){_
int n, m;
cin >> n >> m;
vector<ll> v(n);
vector<ll> w(n);
for (auto &i : v) cin >> i;
for (auto &i : w) cin >> i;
ll vsum = 0;
for (auto &i : v) vsum+=i; // 儲存總價值
vector<ll> dp(m+5, 0);
for (int i = 0; i < n; ++i) {
for (int j = m; j >= w[i]; j--) { // 由上往下
dp[j] = max(dp[j - w[i]] + v[i], dp[j]);
}
}
cout << vsum - dp[m] << endl;
return 0;
}
# PRESENTING CODE
這題其實是防破台題啦哈哈
題序
給你一張長這樣的圖,問你可以自由調整水位高度的同時,最多可以淹出幾座島嶼?
嗯,我原本只打算講這樣
# PRESENTING CODE
這題其實要分為兩個部分來看
# PRESENTING CODE
給你很多條線段的左右端點,請你找到一個x座標,使有通過此x座標的線段數目最多,並且輸出線段的數量
# PRESENTING CODE
要怎麼做勒?
窮舉每個x座標,檢查有幾條線段通過
# PRESENTING CODE
複雜度 \(O(nv)\),其中 \(v\) 為x座標值域
不過我們可以發現一件事
如果我們按x座標順序來檢查
\(i-1\)的線段數目會和 \(i\) 一致,除非...
有線段的其中一端點在\(i\)
所以,我們其實可以只檢查所有有線段端點的x座標就好
但其實,這題應該要壓到\(O(n \log n)\)才會AC
How?
這樣複雜度可以壓到\(O(n^2)\),subtask 1 會過
(如果看得出淹水和線段蘇的關係的話)
作法:
用一個變數s
紀錄當前的線段數,當檢查下一個位置時,
若該點是左端點,則s++
若該點是右端點,則s--
然後另外用一個變數紀錄s曾經出現過的最大值,就是答案了
# PRESENTING CODE
用一個型態為pair<int, int>的陣列
第一項放x座標,第二項則紀錄左端點或右端點
這樣排序複雜度\(O(n \log n)\)
之後只要照陣列順序進行計算s的值
就可以\(O(n \log n + n)\)的時間複雜度解決線段蘇了
# PRESENTING CODE
淹水和線段蘇的關聯?
來觀察一下每塊地形成為島嶼,和水位高度的關係?
# PRESENTING CODE
如果我們去看每一個凸起地方的左邊界(你要右邊界也沒差)
你會發覺
當水位高度在這個範圍時,該地形剛好就會是島嶼
而且不會被重複計算到!
# PRESENTING CODE
所以...把這張圖轉九十度
再加上一個可以自由移動的水位線...
線段蘇問題就出現了!
# PRESENTING CODE
不過要注意的是,所有的線段都是左閉右開
因為水位高度和地形高度相同時不算島嶼
# AC CODE
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define _ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
signed main(){_
int n;
cin >> n;
vector<int> arr(n);
for (int i = 0; i < n; ++i) {
cin >> arr[i]; // 輸入地形
}
int left = 0;
vector<pair<int, int>> seg; // 紀錄線段端點的陣列
for (int i = 0; i < n; ++i) {
if (arr[i] > left) { // 比較當前位置有沒有比他左邊的高
// 有比較高才需要畫線紀錄
seg.pb({left, 1}); // 線段較低處的開始端點,值為+1(會使線段數增加)
seg.pb({arr[i], -1}); // 線段較高處的結束端點,值為-1(會使線段數減少)
}
left = arr[i];
}
sort(seg.begin(), seg.end()); // pair預設的sort方式是先比第一項再比第二項
ll sum = 0, mx = 0;
for (auto i : seg) {
sum += i.second; // 計算經過此端點後的線段數
mx = max(mx, sum); // 取答案的max
}
cout << mx << '\n';
return 0;
}
Going to the Void
# Dynamic Programming
# 學會不要看阿蘇的題敘
# Statement
有一張大小為 \(N×M\) 的圖
以左上角為起點、右下角為終點
其中有 \(R\) 個障礙物在上面
任何有障礙物的地方皆不得進入
請問到終點有多少種最短路徑?
請將答案模 \(10^9+7\) 後輸出
若根本沒有路能到終點,則輸出 "Path No Found."
\(2 \leq N、M \leq 2000\)
\(0 \leq R \leq 1000\)
欸隨便窮舉就有五分了誒,真的不考慮做一下嗎
void solve (){
int N, M, R; cin >> N >> M >> R;
switch (N){
case 2: cout << "2\n"; break;
case 3: cout << "6\n"; break;
case 4: cout << "20\n"; break;
case 5: cout << "70\n"; break;
case 6: cout << "252\n"; break;
case 7: cout << "924\n"; break;
case 8: cout << "3432\n"; break;
case 9: cout << "12870\n"; break;
case 10: cout << "48620\n"; break;
};
}
# PRESENTING CODE
其實我本來這個 subtask 是亂做的
# PRESENTING CODE
數學解思維
# PRESENTING CODE
DP 解思維
到此格的走法 =
到上面那格的走法 + 到左邊那格的走法
const int MAXN = 2017;
vector <vector <int>> graph(MAXN, vector <int>(MAXN, 0));
void solve (){
int N, M, R; cin >> N >> M >> R;
int ans = 0;
for (int i = 1; i <= N; i++){
for (int j = 1; j <= M; j++){
if (i == 1 && j == 1) graph[i][j] = 1;
else graph[i][j] = graph[i-1][j] + graph[i][j-1];
}
}
ans = graph[N][M];
cout << ans << '\n';
}
你以為我那個 mod 是寫好看的嗎
# PRESENTING CODE
$$(a+b)\;\%\;m \; = \; (a\;\%\;m+b\;\%\;m)\;\%\;m$$
$$(a-b)\;\%\;m \; = \; (a\;\%\;m-b\;\%\;m)\;\%\;m$$
$$(a\,b)\;\%\;m \; = \; [(a\;\%\;m)\,(b\;\%\;m)]\;\%\;m$$
ll Mod (ll a, int m = MOD){
return (a+m) % m;
}
ll Plus (ll a, ll b, int m = MOD){
return Mod(Mod(a) + Mod(b));
}
ll Minus (ll a, ll b, int m = MOD){
return Mod(Mod(a) - Mod(b));
}
ll Mult (ll a, ll b, int m = MOD){
return Mod(Mod(a) * Mod(b));
}
# PRESENTING CODE
數學解思維
vector <int> factorial(2007, -1);
void solve (){
int N, M, R; cin >> N >> M >> R;
int tmp = 1;
for (int i = 1; i <= N+M; i++){
tmp = Mult(tmp, i);
factorial[i] = tmp;
}
cout << factorial[N+M] / factorial[N] / factorial[M] << '\n';
}
答案會是爛的。因為同餘定理 不支援除法
你可以套 模反元素 解決此問題,或乾脆換個做法吧
# PRESENTING CODE
DP 解思維
const int MOD = 1e9 + 7;
ll Mod (ll a, int m = MOD){
return (a+m) % m;
}
ll Plus (ll a, ll b, int m = MOD){
return Mod(Mod(a) + Mod(b));
}
const int MAXN = 2017;
vector <vector <int>> graph(MAXN, vector <int>(MAXN, 0));
void solve (){
int N, M, R; cin >> N >> M >> R;
int ans = 0;
for (int i = 1; i <= N; i++){
for (int j = 1; j <= M; j++){
if (i == 1 && j == 1) graph[i][j] = 1;
else graph[i][j] = Plus(graph[i-1][j], graph[i][j-1]);
}
}
ans = graph[N][M];
cout << ans << '\n';
}
剩下的 subtask 是在你寫出 bug 的情況下才會卡到
但我教你們寫 bug 幹嘛
# PRESENTING CODE
void solve (){
for (int i = 0; i < MAXN; i++)
for (int j = 0; j < MAXN; j++)
graph[i][j] = 0;
int N, M, R; cin >> N >> M >> R;
for (int i = 0; i < R; i++){
int x, y; cin >> x >> y;
graph[x][y] = -1;
}
//...
}
# PRESENTING CODE
#include <bits/stdc++.h>
#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long int
using namespace std;
const int MOD = 1e9 + 7;
ll Mod (ll a, int m = MOD){
return (a+m) % m;
}
ll Plus (ll a, ll b, int m = MOD){
return Mod(Mod(a) + Mod(b));
}
const int MAXN = 2017;
vector <vector <int>> graph(MAXN, vector <int>(MAXN, 0));
void solve (){
for (int i = 0; i < MAXN; i++)
for (int j = 0; j < MAXN; j++)
graph[i][j] = 0;
int N, M, R; cin >> N >> M >> R;
for (int i = 0; i < R; i++){
int x, y; cin >> x >> y;
graph[x][y] = -1;
}
for (int i = 1; i <= N; i++){
for (int j = 1; j <= M; j++){
if (graph[i][j] == -1){
graph[i][j] = 0;
continue;
}else if (i == 1 && j == 1){
graph[i][j] = 1;
}else{
graph[i][j] = Plus(graph[i-1][j], graph[i][j-1]);
// printf("At [%d, %d], = %d + %d\n", i, j, graph[i-1][j], graph[i][j-1]);
}
}
}
if (graph[N][M] == 0) cout << "Path No Found.\n";
else cout << graph[N][M] << '\n';
}
int main (){
icisc
solve();
}
雖然他偷偷修正回來,而且沒有發公告,壞透了
# PRESENTING CODE
int N, M, R; cin >> N >> M >> R;
for (int i = 1; i <= N; i++) graph[i][1] = 1;
for (int i = 1; i <= M; i++) graph[1][i] = 1;
正解
bug 解