小 l 計畫進行 \(n\) 場遊戲,每場遊戲使用一張地圖,小 l 會選擇一輛車在該地圖上完成遊戲。
小 l 的賽車有三輛,分別用大寫字母 a、b、c 表示。地圖一共有四種,分別用小寫字母 x、a、b、c 表示。其中,賽車 a 不適合在地圖 a 上使用,賽車 b 不適合在地圖 b 上使用,賽車 c 不適合在地圖 c 上使用,而地圖 x 則適合所有賽車參加。適合所有賽車參加的地圖並不多見,最多隻會有 \(d\) 張。
\(n\) 場遊戲的地圖可以用乙個小寫字母組成的字串描述。例如:\(\underline\) 表示小 l 計畫進行 8 場遊戲,其中第 1 場和第 5 場的地圖型別是 x,適合所有賽車,第 2 場和第 3 場的地圖是 a,不適合賽車 a,第 4 場和第 7 場的地圖是 b,不適合賽車 b,第 6 場和第 8 場的地圖是 c,不適合賽車 c。
小 l 對遊戲有一些特殊的要求(共 \(m\) 條),這些要求可以用四元組 \((i,h_i,j,h_j)\) 來描述,表示若在第 \(i\) 場使用型號為 \(h_i\) 的車子,則第 \(j\) 場遊戲要使用型號為 \(h_j\) 的車子。
你能幫小 l 選擇每場遊戲使用的賽車嗎?如果有多種方案,輸出任意一種方案。如果無解,輸出 「-1」(不含雙引號)。
\(n \le 50000,d \le 8,m\le100000.\)
話說我noi的題改起來好費力啊tat 一道就一天(還對著資料改)不難發現這和之前一道題類似la 3713。
雖然有很多種類,但每個人也只有兩種可以選擇,並且關係也是二元的。
所以我們就可以套2-sat模板了qwq 不會2-sat請點這裡.
首先暴力列舉每個 \(x\) 的狀態,從 \(a,b,c\) 中選取乙個就行了。
然後對於那些二元關係 \((i,h_i,j,h_j)\),就如下考慮。
\(i\) 可以選擇 \(h_i\) 這種賽車
\(j\) 無法選擇 \(h_j\) 這種賽車,那麼 \(i\) 就必不能選 \(h_i\) 了,就連一條 \(h_i \to \lnot h_i\) 的邊(此處 \(\lnot h_i\) 表示 \(i\) 可以選擇的另一種賽車)
\(j\) 可以選擇 \(h_j\) 這種賽車,那麼就只要連 \(h_i \to h_j\) 的邊就好了
\(i\) 不可以選擇 \(h_i\) 這種賽車:那就直接跳過就行了。
然後記得要建逆否命題等價的另一條邊。
如果用dfs複雜度為 \(\theta(3^d nm)\),tarjan就是 \(\theta(3^d (n+m))\) 啦。
其實第二個tarjan複雜度已經足夠過了。。。但是能更優!
有這樣乙個結論:
如果乙個 \(x\) 已經考慮過 \(a,b\) 兩個狀態了,那麼我們就不用考慮為 \(c\) 的狀態。這是為什麼呢?
因為 \((a,b)\) 和 \((b,c)\) 的兩種選擇你都已經考慮過了,那麼剩下一種 \((a,c)\) 你前面一定會在前面一種選過。(因為每個點只能從那三種中選擇一種賽車,如果另外兩種都不可行,剩下一種也不行了)
這樣我們就可以將複雜度降為 \(\theta(2^d(n+m))\) qwq
然而又有垃圾uoj hack資料 我判了一下快到0.8s的時候,直接輸出"-1"...才過 (卡常數真的噁心)
我一開始寫了個dfs的可以跑過85分.... 然而有人能用這個a掉 orz
#include #define for(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define set(a, v) memset(a, v, sizeof(a))
using namespace std;
inline bool chkmin(int &a, int b)
inline bool chkmax(int &a, int b)
inline int read()
void file()
const int n = 100010;
char str[n];
int jump[n], len, last;
int m;
struct limit lt[n];
char opt[n][2];
struct two_sat
void add_edge(int u, int v)
void add(int x, int xv, int y, int yv) //(x,xv) -> (y,yv)
int sta[n], top;
bool dfs(int x)
bool solve() }}
return true;
}} t;
int n;
inline bool check()
if (!flag)
t.add(u, v1, u, v1 ^ 1);}}
return t.solve();
} inline void out()
void dfs(int pos) return ; }
opt[pos][0] = 'b'; opt[pos][1] = 'c'; str[pos] = 'a'; dfs(jump[pos]);
opt[pos][0] = 'a'; opt[pos][1] = 'c'; str[pos] = 'b'; dfs(jump[pos]);
} int main ()
else }
m = read();
for (i, 1, m)
dfs(last);
puts("-1");
return 0;
}
正解就用tarjan縮點就行咯qwq
#include #define for(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define set(a, v) memset(a, v, sizeof(a))
using namespace std;
inline bool chkmin(int &a, int b)
inline bool chkmax(int &a, int b)
inline int read()
void file()
const int n = 200100;
char str[n];
int jump[n], len, last;
int m;
struct limit lt[n];
char opt[n][2];
struct two_sat
void add_edge(int u, int v)
void add(int x, int xv, int y, int yv) //(x,xv) -> (y,yv)
int sccno[n], scc_cnt;
int dfn[n], lowlink[n];
int sta[n], top, clk;
void tarjan(int u)
else if (!sccno[v]) chkmin(lowlink[u], dfn[v]);
}if (lowlink[u] == dfn[u]) }}
bool solve()
void out()
}} t;
int n;
int cnt = 0;
inline bool check()
if (!flag) t.add(u, v1, u, v1 ^ 1);}}
int res = t.solve();
return res;
} void dfs(int pos)
if (pos == len + 1) return ; }
opt[pos][0] = 'a'; opt[pos][1] = 'c'; str[pos] = 'b'; dfs(jump[pos]);
opt[pos][0] = 'b'; opt[pos][1] = 'c'; str[pos] = 'a'; dfs(jump[pos]);
} int main ()
else }
m = read();
for (i, 1, m)
dfs(last); puts("-1");
return 0;
}
UOJ 318 NOI2017 蔬菜 貪心
我怎麼越來越菜了。首先,對於乙個物品,我們將它拆成若干份 最後一天拆成兩份,乙份的個數為1 價值為 a s 另乙份的個數為 c 1 mod x,價值為 a。對於在 c 1 x 天以及以前,每天有乙份個數為 x,價值為 a 的物品。於是,用堆維護物品,每次取最大價值的,就可以在 o n 2 m log...
NOI2017 遊戲 解題報告
d 這麼小,你考慮直接對 d 個東西暴力 列舉 x 為 a 或 b c 就不用了,因為 a,b 已經包含 c 了,剩下的就是個 2 sat 問題了 但是你發現有個情況是,在若 a 即 b 時,如果 b 被 ban 了,那麼 a 也要被 ban 我們記錄一下被 ban 的點,然後在球方案的時候判一下 ...
題解 P3825 NOI2017 遊戲
dfs 2 sat被卡得好開心啊 這道題目乍一看是一道 3 sat 的題目,變數是每個地圖,選擇是車的型別。但要注意乙個事實 除了那d個地圖之外,其它的地圖事實上只有2種選擇。而對於那d個x型地圖,我們可以窮舉假設它是a型或b型,因為a型 b型的合法選擇的並還是x型,所以不影響答案。接下來就是連邊的...