[dp][后缀和] Jzoj P5778 没有硝烟的战争

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。

题解

  • 首先,可以破坏为链,在n后返回到1
  • 设f[i][j]为前i个动物 报的数字为j 是否有必胜策略(0表示没有 1表示有)
  • 那么怎么求f数组
  • 如果当前i和i+1是同一种动物
  • 那只要判断f[i+1][j+1...+k]有没有必胜策略,如果有f[i][j]=1
  • 如果当前i和i+1不是同一种动物
  • 那只要判断f[i+1][j+1...+k]有没有必胜策略,如果有f[i][j]=0
  • 那么判断f[i+1][j+1...+k]有没有必胜策略,只要用一个后缀和统计就好了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6 int f[5010][5010],sum[5010][5010],n,m,q,a[5010];
 7 int quan(int x) {if (x==n) return 1; else return x+1;}
 8 int main()
 9 {
10     //freopen("vode.in","r",stdin);
11     //freopen("vode.out","w",stdout);
12     scanf("%d%d%d",&n,&m,&q);
13     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
14     for (int j=m-2;j>=0;j--)
15         for (int i=1;i<=n;i++)
16         {
17             int mn=j+1,mx=min(j+q,m-1);
18             f[i][j]=(((a[i]^a[quan(i)])&&sum[quan(i)][mn]-sum[quan(i)][mx+1]<mx-mn+1)||(!(a[i]^a[quan(i)])&&sum[quan(i)][mn]-sum[quan(i)][mx+1]>0));
19             sum[i][j]=sum[i][j+1]+f[i][j];
20         }
21     for (int i=1;i<=n;i++) printf("%d ",(1-(f[i][0]^a[i])));
22     return 0;
23 }
原文地址:https://www.cnblogs.com/Comfortable/p/9445161.html