11.4 校內模擬賽解題報告
阿新 • • 發佈:2021-11-04
沒有摘要
之間連一條狀態為 \(k\) 的邊,讓這條邊進隊。
當 \(w < 0\) 的時候邊是不進隊的,因為有了左括號後可以接右括號,而右括號後不能接左括號。
T1
儘量先找面額大的,然後找面額小的。
int main() { n = read(); for(int i = 1; i <= n; i++) { int x = read(); if(x == 5) a++; if(x == 10) { if(a != 0) a--, b++; else {puts("NO"); return 0;} } if(x == 20) { if(b != 0 && a != 0) a--, b--; else if(a >= 3) a -= 3; else {puts("NO"); return 0;} } } puts("YES"); fclose(stdin); fclose(stdout); return 0; }
T2
考場上寫了一個用棧正序維護的錯誤做法,維護棧中每個數字的個數,和已知出口數字的個數,怎麼看怎麼對。但是並不對。
正解:用棧倒敘維護,每次棧頂的絕對值與當前數的絕對值不相同,就將當前數變成負數進棧,如果相同且棧頂為負,則出棧。
/* Date: Source: Knowledge: 用棧維護,倒著來 */ #include <iostream> #include <cstdio> #include <cmath> #define orz cout << "AK IOI" << "\n" using namespace std; const int maxn = 1e6 + 10; int read() { int x = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while(ch <= '9' && ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();} return x * f; } void print(int X) { if(X < 0) X = ~(X - 1), putchar('-'); if(X > 9) print(X / 10); putchar(X % 10 ^ '0'); } int Max(int a, int b){ return a > b ? a : b; } int Min(int a, int b){ return a < b ? a : b; } int n, m, a[maxn], vis[maxn]; int top, st[maxn]; int main() { //freopen("program1.in", "r", stdin); //freopen("program.out", "w", stdout); n = read(); for(int i = 1; i <= n; i++) a[i] = read(), vis[a[i]]++; for(int i = 1; i <= n; i++) if(vis[a[i]] % 2 == 1) {puts("NO"); return 0;} m = read(); for(int i = 1; i <= m; i++) { int x = read(); if(a[x] > 0) a[x] = -a[x]; } for(int i = n; i >= 1; i--) { if(abs(st[top]) != abs(a[i])) { if(a[i] > 0) st[++top] = -a[i], a[i] = -a[i]; else st[++top] = a[i]; } else { if(a[i] > 0) top--; else st[++top] = a[i]; } } for(int i = 1; i <= n; i++) { if(a[i] < 0) printf("%d ", a[i]); else printf("+%d ", a[i]); } fclose(stdin); fclose(stdout); return 0; }
T3
將鑰匙看做左括號,門看做右括號,模擬括號匹配,將問題轉化為 從 \(a\) 走到 \(b\) 能否完成括號匹配。
寬搜 + DP。
\(f[i][j][k]\) 表示點 \(i\) 到點 \(j\) 是否有狀態 \(k\)。
\(k = 0\) 表示 \(i\) 到 \(j\) 的路徑上能夠括號匹配。
\(k:1 — 10\) 表示點 \(i\) 到 \(j\) 的路徑上,棧頂為右括號 \(k\)。
\(k:11 — 20\) 表示點 \(i\) 到 \(j\) 的路徑上,棧頂為左括號 \(k\),即缺右括號 \(k\)。
每次更新一個 \(i \ j \ k\),就相當於在 \(i \ j\)
當 \(w < 0\) 的時候邊是不進隊的,因為有了左括號後可以接右括號,而右括號後不能接左括號。
從佇列裡取出從 \(u\) 到 \(v\) 的狀態為 \(w\) 的邊。
如果 \(w = 0\),那麼列舉狀態 \(k (0, 11—20)\) 進行更新。
如果 \(w != 0\),那麼只能去找右括號。
具體看程式碼。
為什麼 \(w=0\) 是雙向更新,\(w!=0\) 是單項更新?
因為只能是棧中有左括號的情況下,只有右括號才能入棧。
對於每一次詢問,判斷 \(f[u][v][0]\) 即可。
/*
Date:
Source:
Knowledge:f[i][j][k] 表示點i到點j 是否有狀態k
*/
#include <iostream>
#include <cstdio>
#include <queue>
#define orz cout << "AK IOI" << "\n"
using namespace std;
const int maxn = 110;
int read()
{
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch <= '9' && ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
void print(int X)
{
if(X < 0) X = ~(X - 1), putchar('-');
if(X > 9) print(X / 10);
putchar(X % 10 ^ '0');
}
int Max(int a, int b){
return a > b ? a : b;
}
int Min(int a, int b){
return a < b ? a : b;
}
int n, m, Q;
bool f[maxn][maxn][25];
struct node{
int u, v, w;
};
queue <node> q;
int main()
{
n = read(), m = read();
for(int i = 1; i <= n; i++) f[i][i][0] = 1;
for(int i = 1; i <= m; i++)
{
int u = read(), v = read(), w = read();
if(w == 0)
{
f[u][v][w] = f[v][u][w] = 1;
q.push((node){u, v, w});
q.push((node){v, u, w});
}
else if(w > 0)//鑰匙
{
w += 10;
f[u][v][w] = f[v][u][w] = 1;
q.push((node){u, v, w});
q.push((node){v, u, w});
}
else w = -w, f[u][v][w] = f[v][u][w] = 1; //門
}
while(!q.empty())
{
node t = q.front();
q.pop();
int u = t.u, v = t.v, w = t.w;
if(w == 0)//大前提是已經有一條權值為 0 的邊連通 u,v, 此時是一條有向邊, 類比最短路。
{
for(int i = 1; i <= n; i++)
{
if(f[i][u][0] && !f[i][v][0])
{
f[i][v][0] = 1;
q.push((node){i, v, 0});
}
if(f[v][i][0] && !f[u][i][0])
{
f[u][i][0] = 1;
q.push((node){u, i, 0});
}
for(int k = 11; k <= 20; k++)
{
if(f[i][u][k] == 1 && !f[i][v][k]) f[i][v][k] = 1, q.push((node){i, v, k});
//if(f[i][v][k] == 1 && !f[i][u][k]) f[i][u][k] = 1, q.push((node){i, u, k});
}
}
}
else
{
for(int i = 1; i <= n; i++)
{
if(f[v][i][w - 10] && !f[u][i][0]) // w 屬於(1 - 10) 並沒有入隊
{
f[u][i][0] = 1;
q.push((node){u, i, 0});
}
}
}
}
Q = read();
for(int i = 1; i <= Q; i++)
{
int a = read(), b = read();
if(f[a][b][0] == 1) puts("YES");
else puts("NO");
}
//fclose(stdin);
//fclose(stdout);
return 0;
}