• poj 3274 Gold Balanced Lineup(HASH)


    大致题意:Farmer John有N头牛,N最多是10^5 ,每头牛最多有30种特征,一头牛所具有的特征可以用一个数来表示,将这个数化成2进制,第i位上权为1,说明它具有第i种特征,如果有一个区间(牛编号连续),使得这个区间的牛的每种特征之和相等,则这个区间为平衡区间。现在告诉你牛的个数n,特征个数k和每头牛的特征值,让你求最大的平衡区间。

    Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other)

    样例:

    Sample Input

    7 3
    7
    6
    7
    2
    1
    4
    2

    Sample Output

    4

    选择的牛是第3头到第6头

    思路:不妨先统计出前i头牛所有的特征值,则第i头牛到第j头牛的特征值就很容易求了。

    num[i][k]代表前i头牛共有num[i][k]个牛具有第k个特征,如果区间[i,j]满足平衡区间,那么有:

    num[j][0]-num[i][0]=num[j][1]-num[j][1]=...=num[j][k-1]-num[i][k-1]

    想到这里,这个题目应该就是检索了,但是N是10^5,枚举区间时间复杂度是O(k*n^2),10^10量级在2S内是跑不完的,只能优化,尽量缩小检索区间,这里方法有很多,可以根据num基数排序,也可以用HASH。我觉得HASH比较好想:

    上方推导的关系式不是很易于检索,也不好确定键值,于是我们对上面的等式稍稍变形:

    num[j][0]-num[i][0]=num[j][1]-num[j][1],我们可以得到num[j][0]-num[j][1]=num[i][0]-num[i][1],那么:

    num[j][0]-num[j][1]=num[i][0]-num[i][1],num[j][0]-num[j][2]=num[i][0]-num[i][2]...num[j][0]-num[j][k-1]=num[i][0]-num[i][k-1]

    这样我们可以预处理每一个num序列,设sub[i][j]=num[i][0]-num[j],则问题就转化为求最大的区间[i,j],使得sub[i]和sub[j]这两个数组的第1~k-1个元素相等。

    直接寻找的时间复杂度仍是O(k*n^2),但我们比较容易对sub数组进行HASH。HASH的方法是将sub[i]十进制转化,超出数组范围就取余,链表存储具有相同键值的元素,然后对N个数据直接在相应的链表中查询,更新最大值即可。假设每组链中的元素远小于N,并且忽略k(k比较小),那么我们就能够在小于O(n^2)的时间内检索出结果。

    还算是比较简单的数据结构题吧。

    这题有USACO官方题解和数据,数据链接:

    http://ace.delos.com/TESTDATA/MAR07_4.htm

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 using namespace std;
     5 const int MAXNUM=100003;
     6 struct stru{
     7     int num[31],dx;
     8     stru *next;
     9 };
    10 stru str[MAXNUM+5];
    11 int num[MAXNUM][31],n,k;
    12 bool is(int n1[],int n2[]){
    13     for(int i=0;i<k-1;i++){
    14         if(n1[i]!=n2[i+1])return false;
    15     }
    16     return true;
    17 }
    18 int main(){
    19     int i,j;
    20     while(~scanf("%d%d",&n,&k)){
    21         if(k==1){printf("%d\n",n);continue;}  //不知道有没有k=1的数据,也不确信算法是否能够解决k=1时的最长区间,不过答案显而易见,索性直接输出
    22         memset(num,0,sizeof(num));
    23         memset(str,0,sizeof(str));
    24         for(i=1;i<=n;i++){
    25              int temp;
    26              scanf("%d",&temp);
    27              for(j=0;j<k;j++){
    28                  num[i][j]=num[i-1][j]+temp%2;
    29                  temp>>=1;
    30              }
    31          }
    32          for(i=0;i<=n;i++){  //这里不要忘了把第一组全0序列也加进去
    33              for(j=1;j<k;j++)num[i][j]-=num[i][0];
    34              int temp=0;
    35              for(j=1;j<k;j++){  //HASH
    36                 temp=(temp+num[i][j]);
    37                 temp%=MAXNUM;
    38                 if(j!=k-1)temp*=10;
    39              }
    40              temp=(temp%MAXNUM+MAXNUM)%MAXNUM;
    41              num[i][0]=temp;
    42              stru *s=new stru;
    43              s->next=NULL;s->dx=i;  //一定要将s->next设成空,很多题因此RE过很多次
    44              for(j=1;j<k;j++)s->num[j-1]=num[i][j];
    45              s->next=str[temp].next;
    46              str[temp].next=s;
    47          }
    48          int ans=-(int)1e10;
    49          for(i=1;i<=n;i++){  //寻找最大区间
    50              stru *temp=&str[num[i][0]];
    51              while(temp->next!=NULL){
    52                  if(is(temp->next->num,num[i])){
    53                      ans=ans>i-temp->next->dx?ans:i-temp->next->dx;
    54                  }
    55                  temp=temp->next;
    56              }
    57          }
    58          printf("%d\n",ans);
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    day23 GUI
    day17JDK5.0新特性与正则表达式
    day12-day15集合
    day11线程
    day10-JavaAPI
    day09面向对象-
    day08面向对象-内部类、异常
    day06面向对象
    Idea导入Eclipse中的Maven Web(SSM)
    java给图片添加水印
  • 原文地址:https://www.cnblogs.com/mcflurry/p/2554490.html
Copyright © 2020-2023  润新知