/*
n個數,求最長的連續一段,使得這一段數字,二進制中每一位擁有1的那些數字的個數相等
n<=10^5,位數k<=30
如
7 2 1 4 這里每一位1都有2個數字擁有
容易想到先預處理出sum[n,k]表示前面n個數字中在第k位是1的個數
這k個數字sum[n,k]的樣子就是曲線形的,如sum[i,k]為
_ /\
/ \/ \_/\
為了使得sum[i,k] - sum[j,k]對所有k都是同一個數
則sum[j,k]的樣子也必須是這樣的,這樣sum[i,k] - sum[j,k]才是一個同一個數(類似拼接時圖形需吻合)
好了,所以我們需要保存這個圖形,可以通過保存a[i,k] = sum[i,k] - sum[i,0]即可(即保存相對值) -----OMG
我一開始用map<vector<int>, int>, vector<int>是保存圖形,int是保存第一次出現的地方
在for到i時,計算出圖形,在map中找有沒出現過,有的話就更新答案為i-mp[vt]
vector是有重載比較運算符的,所以不用寫其他
但是超時了,我在本機測貌似不會超時 --||
看了解題報告,方法一樣,但是不是用map,是最后sort一次的
對哦,我想起之前也有一道題,又不需要每個i都輸出結果,不用map,直接最后sort一次更好
用map會慢一點
但這樣還超時,原來是vector的比較比較慢
自己寫了個struct Node {int vt[30];}; 再重載比較過了
sort時,可以對下標排序,減少了大數據移動
這題官方有另外解法,就是對數組vt[30] hash
好的hash函數會快很多吧
hsize=997001;
for(p=0,i=0;i<k;i++)
p=((p<<2)+(v[i]>>4))^(v[i]<<10);
p=p%hsize;
if(p<0) p+=hsize;
*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cstring>
#include<cmath>
#include<string>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<set>
#include<list>
#include<numeric>
#include<cassert>
#include<sstream>
#include<ctime>
#include<bitset>
#include<functional>
using namespace std;
const int MAXN = 100100;
int n, k;
struct Node
{
int vt[30];
void clear()
{
memset(vt, 0, sizeof vt);
}
};
bool operator < (const Node &A, const Node &B) //直接用vector的比較會慢 可能數據太大吧
{
for (int i = 0; i < k - 1; i++) {
if (A.vt[i] != B.vt[i]) {
return A.vt[i] < B.vt[i];
}
}
return false;
}
pair<Node, int> all[MAXN];
inline bool cmp(const int &a, const int &b)
{
return all[a] < all[b];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif
for (; ~scanf("%d%d", &n, &k); ) {
// long long start = clock();
vector<int> vt(k-1), pos(n+1);
all[0].first.clear();//don't forget to push k-1 zeros
all[0].second = 0;
pos[0] = 0;
vector<int> sum(k);
for (int i = 1, x; i <= n; i++) {
scanf("%d", &x);
for (int j = 0; j < k; j++) {
sum[j] += (x>>j) & 1;
if (j > 0) {
all[i].first.vt[j-1] = sum[j] - sum[j-1];
}
}
all[i].second = i;
pos[i] = i;
}
sort(pos.begin(), pos.end(), cmp);
int ans = 0;
for (int i = 1, last = 0; i <= n+1; i++) {
if (i == n+1 || all[pos[i-1]].first < all[pos[i]].first) {
ans = max(ans, all[pos[i-1]].second - all[pos[last]].second);
last = i;
}
}
printf("%d\n", ans);
// cout<<"time "<<clock() - start<<endl;
}
return 0;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|