码迷,mamicode.com
首页 > 其他好文 > 详细

JZOJ 5778

时间:2018-08-08 22:33:11      阅读:289      评论:0      收藏:0      [点我收藏+]

标签:++   class   顺时针   getch   +=   main   cst   sdi   turn   

Description

被污染的灰灰草原上有羊和狼。有N只动物围成一圈,每只动物是羊或狼。

该游戏从其中的一只动物开始,报出[1,K]区间的整数,若上一只动物报出的数是x,下一只动物可以报[x+1,x+K]区间的整数,游戏按顺时针方向进行。每只动物报的数字都不能超过M。

若一只动物报了M这个数,它所在的种族就输了。问以第i只动物为游戏的开始,最后哪种动物会赢?

Input

第一行输入三个正整数N,M,K。

接下来一行N个正整数,分别表示N只动物的种类,以顺时针的方向给出。0代表羊,1代表狼。

Output

一行输出N个整数,表示若从第i只动物开始,赢的动物的种类。同上,0代表羊,1代表狼。

Sample Input

Input 1

2 9 2
0 1


Input 2

6 499 5
1 0 0 1 1 0


Input 3

10 100 10
0 0 0 1 1 1 1 0 1 1


Sample Output

Output 1

0 1


Output 2

0 1 1 1 1 0


Output 3

1 1 1 1 1 1 1 1 1 1


Data Constraint

对于60%的数据,1 ≤ N, M, K ≤ 500。

对于100%的数据,1 ≤ N, M, K ≤ 5000。


 

一开始以为结论博弈题,玩了玩发现好像并不是

又以为是 SG 函数,心想只能打暴力了

yy 了一下写了个 dp  (差点就写对了?

一开始觉得破环成链复制出来 m 个很虚,也没敢接着想

反正状态是错的:f[i][j] 表示第 i 个数第 j 个人选是必胜还是必败

还有带个线段树优化成 O(n ^ 2 * logn)

居然还有8分

 

正解是这样的

f[i][j] 表示 在位置 i 这个人选择 j 这个数是必胜还是必败

最多每个人都选择增大 1 ,所以将人复制成为 n + m 个

边界:所有人选 m 都是必败,第 n + m - 1 个人只能选 1, 也是必败,就不用更新他了

倒着递推出之前的

f[i][j] 从 f[i][j + 1] ~ f[i][j + k] 更新

判断上一个人是不是队友,是队友只要有必胜态,此状态还是必胜

不是队友只要有必胜态,此状态为必败态,否则必胜

什么前缀和线段树什么的随便优化一下就好了


代码:

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cstdio>
using namespace std;

const int MAXN = 5005;

int n, m, k;
int per[MAXN << 1], f[MAXN << 1][MAXN];

inline int rd() {
	register int x = 0;
	register char c = getchar();
	while(!isdigit(c)) c = getchar();
	while(isdigit(c)) {
		x = x * 10 + (c ^ 48);
		c = getchar();
	}
	return x;
}

int main() {
	freopen("vode.in", "r", stdin);
	freopen("vode.out", "w", stdout);
	n = rd(); m = rd(); k = rd();
	for(int i = 1; i <= n; ++i) per[i] = rd();
	int ptr = n;
	while(ptr < m + n) {
		++ptr;
		per[ptr] = per[ptr - n];
	}
	for(int i = n + m - 2; i >= 1; --i) {
		int pre = 0;
		for(int j = m - 1; j >= 1; --j) {
			f[i][j] = ((per[i] == per[i + 1]) ? (!(pre == 0)) : (pre == 0)); 
			pre += f[i + 1][j];
			if(m - j + 1 >= k) pre -= f[i + 1][j + k];
		}
	}
	for(int i = 1; i <= n; ++i) {
		bool win = false;
		for(int j = 1; j <= k; ++j) win |= f[i][j];
		printf("%d ", win ? per[i] : (per[i] ^ 1));
	}
	return 0;
}

  

 

JZOJ 5778

标签:++   class   顺时针   getch   +=   main   cst   sdi   turn   

原文地址:https://www.cnblogs.com/xcysblog/p/9446016.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!