BZOJ1702: [Usaco2007 Mar]Gold Balanced Lineup 平衡的队列
n<=100000个数表示每头牛在K<=30种物品的选取情况,该数在二进制下某位为0表示不选1表示选,求一个最大的区间使区间内选择每种物品的牛一样多。
数学转化,把不同状态间单变量的关系通过不等式移项转变为单状态的多变量关系。
sum[i,j]表示前i头牛有多少选了物品j,那么问题要求即对任意j∈[1,K],sum[p,j]-sum[q,j]相等,使p-q最大。(多状态,单变量)
列出来,sum[p,1]-sum[q,1]=sum[p,2]-sum[q,2]=……,移项,sum[p,2]-sum[p,1]=sum[q,2]-sum[q,1],sum[p,j]-sum[p,1]=sum[q,j]-sum[q,1],j∈[2,K]。
最后需要比较的就是每个i的sum[i,j]-sum[i,1]是否相同。(单状态,多变量)
找“最远的与当前数相同的数”,方法多样,这里用hash。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 //#include<iostream> 6 using namespace std; 7 8 int n,K; 9 #define maxn 100011 10 typedef int state[31]; 11 #define maxh 100007 12 const int inf=0x3f3f3f3f; 13 int ans; 14 struct Hash 15 { 16 int first[maxh]; 17 struct Node 18 { 19 state list; 20 int Max,Min; 21 int next; 22 }a[maxn]; 23 int size; 24 Hash() 25 { 26 memset(first,0,sizeof(first)); 27 size=0; 28 } 29 int hash(state s) 30 { 31 int v=0; 32 for (int i=1;i<K;i++) 33 v=(v*233+s[i])%maxh; 34 return (v+maxh)%maxh; 35 } 36 bool equal(state a,state b) 37 { 38 for (int i=1;i<K;i++) 39 if (a[i]!=b[i]) return 0; 40 return 1; 41 } 42 void insert(state s,int p) 43 { 44 int v=hash(s); 45 for (int i=first[v];i;i=a[i].next) 46 if (equal(s,a[i].list)) 47 { 48 a[i].Max=max(a[i].Max,p); 49 ans=max(ans,a[i].Max-a[i].Min); 50 return; 51 } 52 int x=++size; 53 for (int i=1;i<K;i++) a[x].list[i]=s[i]; 54 a[x].Max=a[x].Min=p; 55 a[x].next=first[v]; 56 first[v]=x; 57 } 58 }h; 59 state sum; 60 int x; 61 int main() 62 { 63 scanf("%d%d",&n,&K); 64 memset(sum,0,sizeof(sum)); 65 ans=0; 66 h.insert(sum,0); 67 for (int i=1;i<=n;i++) 68 { 69 scanf("%d",&x); 70 int j=1; 71 while (x) 72 { 73 sum[j]+=x&1; 74 j++;x>>=1; 75 } 76 state now; 77 for (int j=1;j<K;j++) 78 now[j]=sum[j+1]-sum[1]; 79 h.insert(now,i); 80 } 81 printf("%d\n",ans); 82 return 0; 83 }