BZOJ 2940 条纹

题目大意

条纹游戏是一个双人的游戏。所需要的物品有一个棋盘以及三种颜色的长方形条纹,这三种颜色分别是红色、绿色和蓝色。红色条纹的尺寸是 c × 1 c\times 1 c×1,绿色条纹的尺寸是 z × 1 z\times 1 z×1,蓝色条纹的尺寸是 n × 1 n\times 1 n×1。这里 c , z , n c,z,n c,z,n是正整数,每个游戏者都拥有每种颜色的条纹无限个。

一个棋盘是尺寸为 p × 1 p\times 1 p×1长方形。玩家轮流走,每一步都是由一个游戏者任选一种长方形条纹覆盖到棋盘上,并要求遵循以下规则:

  • 条纹不能伸出棋盘之外
  • 不能覆盖在已有的条纹之上
  • 条纹的边缘必须与棋盘方格的边缘相重叠

第一个不能移动的玩家输。

总共有 m m m个棋盘。对于每个棋盘,问先手是否有必胜策略。有则输出 1 1 1,否则输出 2 2 2

数据范围

1 ≤ c , z , n ≤ 1000 , 1 ≤ m ≤ 1000 , 1 ≤ p ≤ 1000 1\leq c,z,n\leq 1000,1\leq m\leq 1000,1\leq p\leq 1000 1c,z,n1000,1m1000,1p1000


题解

s g [ i ] sg[i] sg[i]表示棋盘为 i × 1 i\times 1 i×1时的状态。根据不同条纹的放法,可以得出转移式

s g [ i ] = m e x { s g j ⊕ s g i − j − c , s g j ⊕ s g i − j − z , s g j ⊕ s g i − j − n } sg[i]=mex\{sg_j\oplus sg_{i-j-c},sg_j\oplus sg_{i-j-z},sg_j\oplus sg_{i-j-n}\} sg[i]=mex{sgjsgijc,sgjsgijz,sgjsgijn}

那么,我们可以枚举 i , j i,j i,j,用 O ( p 2 ) O(p^2) O(p2)求出所有 s g i sg_i sgi。接下来,对于每一个 p p p,可以 O ( 1 ) O(1) O(1)求出 s g p sg_{p} sgp

时间复杂度为 O ( p 2 + m ) O(p^2+m) O(p2+m)

code

#include
using namespace std;
int a,b,c,m,z[1005],sg[1005];
int main()
{
	scanf("%d%d%d",&a,&b,&c);
	for(int i=1;i<=1000;i++){
		for(int j=0;j<=1000;j++) z[j]=0;
		for(int j=0;j<=i;j++){
			if(a+j<=i) z[sg[j]^sg[i-j-a]]=1;
			if(b+j<=i) z[sg[j]^sg[i-j-b]]=1;
			if(c+j<=i) z[sg[j]^sg[i-j-c]]=1;
		}
		int x=0;
		for(;z[x];x++);
		sg[i]=x;
	}
	scanf("%d",&m);
	for(int i=1,x;i<=m;i++){
		scanf("%d",&x);
		if(sg[x]) printf("1\n");
		else printf("2\n");
	}
	return 0;
}

你可能感兴趣的:(题解,c++,题解)