1. 程式人生 > 實用技巧 >題解 [POI2013]SPA-Walk

題解 [POI2013]SPA-Walk

題目傳送門

題目大意

給出兩個長度為 \(n\)\(01\) 串,問是否可以通過某一位把 \(s\) 變為 \(t\),但是中途不能變為 \(k\)\(01\) 串中任意一個,問是否可行。

\(n\le 60,n\times k\le 5\times 10^6\)

思路

拖了 1 年多,1 年前打了一個雙向 BFS ,騙了 \(60\) 分(為我後面看別人的 AC 程式碼打下了良好基礎 (倫敦霧,1 年後,在看了題解之後成功 A 掉此題,我成功了,我不再是以前的那個我了。

好吧,還是言歸正傳,其實這道題就是一個爆搜然後加上一個剪枝,剪枝就是說你最多隻搜 \(n\times k\) 個點,至於為什麼我就不知道了。(不過題面都給了 \(n\times k\le 5\times 10^5\)

難道提示還不明顯麼?)證明的話可以參考 這篇題解 ,反正我是沒有看懂。

\(\texttt{Code}\)

using namespace std;

#define Int register int
#define ll long long
#define MAXN 5000005
#define MAXM 1000005
#define mod 2737321

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

ll a[MAXM],to[MAXN],q[MAXN];
int n,k,cnt,h,t,nxt[MAXN],head[mod + 5];

ll getins (){
	ll s = 0;
	for (Int i = 0,x;i < n;++ i) scanf ("%1d",&x),s = (s << 1) | x;
	return s;
}

void ins (ll x){
	to[++ cnt] = x,nxt[cnt] = head[x % mod],head[x % mod] = cnt;
}

void add (ll x){
	for (Int i = head[x % mod];i;i = nxt[i])
		if (to[i] == x) return ;
	ins (x),q[++ t] = x;
}

void BFS (ll S,ll T){
	h = 1,t = cnt = 0;
	memset (head,0,sizeof (head));
	for (Int i = 1;i <= k;++ i) ins (a[i]);
	add (S);
	while (h <= t && t <= n * k){
		ll now = q[h ++];
		if (now == T) puts ("TAK"),exit (0);
		for (Int i = 0;i < n;++ i) add (now ^ (1ll << i));
	}
	if (t <= n * k) puts ("NIE"),exit (0);
}

signed main(){
	read (n,k);ll S = getins (),T = getins ();
	for (Int i = 1;i <= k;++ i) a[i] = getins ();
	BFS (S,T),BFS (T,S);
	puts ("TAK"); 
	return 0;
}