ABC206 F - Interval Game 2 (区间DP,博弈论,SG函数)

题面

题意很简单

A l i c e \tt Alice Alice B o b \tt Bob Bob 在博弈。摆在他们面前有 N \rm N N 个区间 [ l i , r i ) \rm[l_i,r_i) [li,ri) ,每人轮流取出一个区间,放到数轴上,要求取出的区间与当前数轴上的任意区间交集为 ∅ \rm\empty A l i c e \tt Alice Alice 先手。

T ( 1 ≤ T ≤ 20 ) \rm T(1\leq T\leq20) T(1T20) 组数据,每组数据给出 N ( 1 ≤ N ≤ 100 ) \rm N(1\leq N\leq100) N(1N100) 和每个区间 [ l i , r i ) \rm[l_i,r_i) [li,ri) 1 ≤ l i < r i ≤ 100 \rm1\leq l_i1li<ri100

对于每组数据输出 A l i c e \tt Alice Alice 必胜还是 B o b \tt Bob Bob 必胜。

题解

前置知识:SG函数

通过SG定理的学习,我们知道一个游戏先手必败当且仅当SG值为 0 0 0,且多个子游戏同时进行的情况下,总游戏的SG值为每个子游戏SG值的异或和。


这道题怎么应用呢?

毫无疑问, 2 N \rm 2^N 2N 的算法是不行的,那我们怎么表示总游戏的状态呢?

我们表示不出来!但是我们会发现,总游戏可以分成多个互不干扰的子游戏,而每个子游戏是可以用一个区间 [ L , R ) \rm[L,R) [L,R) 表示状态的!意为左右端点都在 [ L , R ) \rm[L,R) [L,R) 内的所有区间 [ l i , r i ) \rm[l_i,r_i) [li,ri) 组成的子游戏。因为每个子游戏成为无法拆分的一部分时,意味着这个范围内的区间彼此通过非空的交集连通在一起,并且 [ L , R ) \rm[L,R) [L,R) 内的所有区间都没被取走。

如果在某个子游戏的范围 [ L , R ) \rm[L,R) [L,R) 内取走了一个区间 [ l , r ) \rm[l,r) [l,r),那么这个子游戏就会被分成两个独立子游戏 [ L , l ) \rm[L,l) [L,l) [ r , R ) \rm[r,R) [r,R)。与之前做过的一道题【CF1523G】Try Booking 类似,并不难理解。

此外,如果对于两个子游戏 [ L , R ) \rm[L,R) [L,R) [ L ′ , R ′ ) \rm[L',R') [L,R) ,在 [ L , R ′ ) \rm[L,R') [L,R) 范围内的区间都没被取走的话,是可以把两个子游戏合并为游戏 [ L , R ′ ) \rm[L,R') [L,R) 的,这不影响。


于是我们可以区间 D P \tt DP DP 了,令 S G L , R \rm SG_{L,R} SGL,R 表示游戏 [ L , R ) \rm[L,R) [L,R)SG函数值,那么就可以转移了:( m e x \rm mex mex 是什么意思不用赘述了吧)
S G L , R = m e x   { ( S G L , l i   x o r   S G r i , R )   ∣   [ l i , r i ) ⊆ [ L , R ) } \rm SG_{L,R}=mex\,\{(SG_{L,l_i}~{\tt xor}~SG_{r_i,R})~|~[l_i,r_i)\sube[L,R)\} SGL,R=mex{(SGL,li xor SGri,R)  [li,ri)[L,R)}

这里有个小细节:计算SG函数值时,如果是递归,那么只能开临时数组。原因不用赘述。

时间复杂度 O ( T ⋅ ∣ U ∣ 2 ⋅ N ) \rm O(T\cdot|U|^2\cdot N) O(TU2N)

CODE

dp 代替了 SG

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN 105
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) ((-x) & (x))
LL read() {
	LL f=1,x=0;char s = getchar();
	while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
	return f * x;
}
int n,m,i,j,s,o,k;
int L[MAXN],R[MAXN];
vector<int> bu[MAXN];
bool f[MAXN][MAXN];
int dp[MAXN][MAXN];
bool tmp[105];
int solve(int l,int r) {
	if(l>r) return 0;
	if(f[l][r]) return dp[l][r];
	f[l][r] = 1;
	int tmp[105];
	memset(tmp,0,sizeof(tmp));
	
	for(int i = l;i <= r;i ++) {
		for(int j = 0;j < (int)bu[i].size();j ++) {
			int ll = L[bu[i][j]],rr = R[bu[i][j]];
			if(rr <= r) {
				tmp[solve(l,ll) ^ solve(rr,r)] = 1;
			}
		}
	}
	for(int i = 0;i <= 101;i ++) {
		if(!tmp[i]) {
			dp[l][r] = i;
			break;
		}
	}
	return dp[l][r];
}
int main() {
	int T = read();
	while(T --) {
		n = read();
		for(int i = 1;i <= 100;i ++) bu[i].clear();
		memset(f,0,sizeof(f));
		memset(dp,0,sizeof(dp));
		for(int i = 1;i <= n;i ++) {
			L[i] = read();R[i] = read();
			bu[L[i]].push_back(i);
		}
		int ans = solve(1,100);
		printf(ans>0 ? "Alice\n":"Bob\n");
	}
	return 0;
}

你可能感兴趣的:(动态规划,数学)