题目描述
小 F 在许多方面都有着很强的能力。她总共有 m 种能力,这些能力编号为 1,...,m。
小 F 每天都会有一些能力得到一次提升。每天的能力提升可以用一个数字表示, 称之为能力提升数字,该数字的二进制位从低到高(即从右到左)第 i 位是 1 表示编号为 i的能力得到了一次提升。比如能力提升数字 13,转化为二进制为 1101,表示编号为 1,3,4 的能力(注意不是 1, 2, 4)分别得到了一次提升。
小 F 把每天的能力提升数字的记了下来,如果在连续的一段时间内,她的每项能力都提升了相同的次数,她就会称这段时间为一段均衡时期,比如在第 3∼6 天,她的每种能力都提升了 2 次,那么这就是一段长度为 4 的均衡时期。
于是问题来了,给出小 F 在 n 天内的能力提升数字,请求出均衡时期的最大长度。
输入格式
第一行有两个整数 n,m,表示有 n 天,m 种能力。
接下来有 n 行,每行有一个整数,分别表示第 1,...,n 天的能力提升数字。 能力提升数字转化为二进制后,从低到高的每一位表示对应的能力是否在当天 得到了一次提升。
输出格式
输出只有一个整数,表示长度最大的均衡时期的长度。
数据范围
对于 50% 的数据,1≤n≤1000。
对于 100% 的数据,1≤n≤10^5,1≤m≤30。
Solution
非常有意思的题目,初看没有思路,后来想到了前缀和,然后暴力枚举端点拿了50%的分数,然后我们可以发现,举个例子,假设前j个数字最后的状态为2 9 10 8,前i个状态为0 7 8 6,则i,j段是平衡的,我们可以发现我们能用一种方式来表达他们,即固定某一位为0,此时只要判断两个端点相同即可求出一段平衡,使用vector存状态,是用map存对应状态第一次出现的位置,更新答案就判断这一状态是否出现过,出现过就拿当前位置减去最早出现的位置。
Code
1 #include<bits/stdc++.h>
2 using namespace std;
3 #define max(a,b) a>b?a:b
4 map<vector<int>,int> Ma;
5 int main()
6 {
7 int N,M,Ans=-1;
8 scanf("%d%d",&N,&M);
9 vector<int> Q;
10 Q.resize(M);
11 Ma[Q]=1;
12 for(int __=1;__<=N;__++){
13 int X,Key=1;
14 scanf("%d",&X);
15 for(int i=0;i<M;i++){
16 if(X&(1<<i)) Q[i]++;
17 if(!Q[i]) Key=0;
18 }
19 for(int i=0;i<M;i++)
20 Q[i]-=Key;
21 if(Ma[Q]) Ans=max(Ans,__-Ma[Q]+1);
22 else Ma[Q]=__+1;
23
24 }
25 if(Ans<0)
26 cout<<Ans;
27 else cout<<0;
28 return 0;
29 }