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; }
原文地址:https://www.cnblogs.com/xcysblog/p/9446016.html