hdu4749

题意来自
题目大意:学校要举办一场典礼,要从n个学生中选若干支队伍来,每支队伍有m个人。然后现在将学生的身高划分成k个等级,接着按照学生的顺序给出学生的身高等级,再然后,给出m个人的队伍要求的相对高度。然后要求从n个中间挑选连续的m个人,满足相对高度即可组成一支队伍。问说最多可以组成多少支队伍。

解题思路:KMP算法的变形,只不过在判断相等的时候有点难办,因为它算的是相对高度,就是同一支队伍中,对应比自己高的个数,相等的个数,比自己矮的个数都要和要求的相等,所以要开一个cx,cy数组,将KMP中判断相等写成一个函数。

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NavigableSet;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class Main {

    public static void main(String[] args) throws IOException{

           StreamTokenizer cin = new StreamTokenizer(new BufferedInputStream(System.in)) ; 
           InputReader in = new InputReader(System.in)  ;
           PrintWriter out = new PrintWriter(System.out) ;  

           while(cin.nextToken() != cin.TT_EOF){
                   int n = (int) cin.nval ;
                   cin.nextToken() ; int m = (int) cin.nval ;
                   cin.nextToken() ; int k = (int) cin.nval ;
                   new Task().solve(cin , n , m , k , out);   //out.flush() ; 
           }

           out.flush() ;

    }

}

class  Task{

    static  final int  maxn = 100008 ;
    static int[]  Next = new int[maxn] ;
    static int[]  a = new int[maxn]  ; 
    static int[]  b = new int[maxn]  ; 
    static int[][]  sa = new int[maxn][26]  ;
    static int[][]  sb = new int[maxn][26]  ;
    int  n , m , k ;

    boolean  ok1(int i , int j){
         int l1 , l2 , e1 , e2 ;
         l1 = l2 = e1 = e2 = 0 ;
         for(int t = 1 ; t <= k ; t++){
             if(t < b[i])
                l1 += sb[i][t] - sb[i-j][t] ;
             else if(t == b[i])
                e1 += sb[i][t] - sb[i-j][t] ;
             if(t < b[j])
                l2 += sb[j][t]  ;
             else if(t == b[i])
                e2 += sb[j][t]  ;
         }
         return l1==l2 && e1==e2 ;
    }

    boolean  ok2(int i , int j){
         int l1 , l2 , e1 , e2 ;
         l1 = l2 = e1 = e2 = 0 ;
         for(int t = 1 ; t <= k ; t++){
             if(t < a[i])
                l1 += sa[i][t] - sa[i-j][t] ;
             else if(t == a[i])
                e1 += sa[i][t] - sa[i-j][t] ;
             if(t < b[j])
                l2 += sb[j][t] ;
             else if(t == b[j])
                e2 += sb[j][t] ;
         }
         return l1==l2 && e1==e2 ;
    }

    void getNext(){
         int i,j;
         j=0;
         Next[1]=0;
         for(i=2;i<=m;i++){
            while(j>0 && !ok1(i , j+1))
                j=Next[j];
            if(ok1(i , j+1))
                j++;
            Next[i]=j;
         }
     }


    int kmp(){
         int i,j;
         int cnt=0;
         j=0;   // 初始状态为 0
         for(i=1;i<=n;i++){
             while(j>0 && !ok2(i,j+1))
                j=Next[j];
            if(ok2(i , j+1))
                j++;
            if(j == m){
                cnt++;
                j = 0 ; //特殊处理一下
            }
         }
         return cnt;
     }



       void   solve(StreamTokenizer cin , int n , int m , int k , PrintWriter out) throws IOException{
               this.n = n ; 
               this.m = m ;
               this.k = k ;
               for(int i = 0 ; i <= n ; i++) Arrays.fill(sa[i] , 0) ;
               for(int i = 0 ; i <= n ; i++) Arrays.fill(sb[i] , 0) ;

               for(int i = 1 ; i <= n ; i++){
                     cin.nextToken() ; a[i] = (int)cin.nval  ;
                     for(int j = 1 ; j <= k ; j++)  sa[i][j] = sa[i-1][j] ;
                     sa[i][a[i]]++ ;
               }
               for(int i = 1 ; i <= m ; i++){
                     cin.nextToken() ; b[i] = (int)cin.nval  ;
                     for(int j = 1 ; j <= k ; j++)  sb[i][j] = sb[i-1][j] ;
                     sb[i][b[i]]++ ;
               }
               getNext() ;

               out.println(kmp()) ;

       }
} 

class   InputReader{
        public BufferedReader   reader ;
        public StringTokenizer  tokenizer ;

        public InputReader(InputStream stream){
               reader = new BufferedReader(new InputStreamReader(stream), 32768) ;
               tokenizer = null ;
        }

        public String next(){
               while(tokenizer == null || ! tokenizer.hasMoreTokens()){
                        try{
                            tokenizer = new StringTokenizer(reader.readLine());
                        }catch (IOException e) {
                             throw new RuntimeException(e);
                        }
               }
               return tokenizer.nextToken();  
        }

        public int  nextInt(){
                    return Integer.parseInt(next());
        }

        public long nextLong(){
                    return Long.parseLong(next());
        }

        public double nextDouble(){
                    return  Double.parseDouble(next());
        }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值