• 【bzoj2081】[Poi2010]Beads Hash


    题目描述

    Zxl有一次决定制造一条项链,她以非常便宜的价格买了一长条鲜艳的珊瑚珠子,她现在也有一个机器,能把这条珠子切成很多块(子串),每块有k(k>0)个珠子,如果这条珠子的长度不是k的倍数,最后一块小于k的就不要拉(nc真浪费),保证珠子的长度为正整数。 Zxl喜欢多样的项链,为她应该怎样选择数字k来尽可能得到更多的不同的子串感到好奇,子串都是可以反转的,换句话说,子串(1,2,3)和(3,2,1)是一样的。写一个程序,为Zxl决定最适合的k从而获得最多不同的子串。 例如:这一串珠子是: (1,1,1,2,2,2,3,3,3,1,2,3,3,1,2,2,1,3,3,2,1), k=1的时候,我们得到3个不同的子串: (1),(2),(3) k=2的时候,我们得到6个不同的子串: (1,1),(1,2),(2,2),(3,3),(3,1),(2,3) k=3的时候,我们得到5个不同的子串: (1,1,1),(2,2,2),(3,3,3),(1,2,3),(3,1,2) k=4的时候,我们得到5个不同的子串: (1,1,1,2),(2,2,3,3),(3,1,2,3),(3,1,2,2),(1,3,3,2)

    输入

    共有两行,第一行一个整数n代表珠子的长度,(n<=200000),第二行是由空格分开的颜色ai(1<=ai<=n)。

    输出

    也有两行,第一行两个整数,第一个整数代表能获得的最大不同的子串个数,第二个整数代表能获得最大值的k的个数,第二行输出所有的k(中间有空格)。

    样例输入

    21
    1 1 1 2 2 2 3 3 3 1 2 3 3 1 2 2 1 3 3 2 1

    样例输出

    6 1


    题解

    Hash

    处理不同字符串问题,Hash是个好方法。

    然而这道题要求反过来的字符串与原串算作同一种,所以Hash值也应相同。

    一种比较简单且容易实现的方法是把它们正反做两次Hash,然后把它们乘起来作为新的Hash值,因为乘法满足交换率。

    这里为了防止被卡取了两个底数进行Hash。

    最终使用map判断就行了。

    时间复杂度为$O(nlog n*log n)=O(nlog^2n)$

    #include <cstdio>
    #include <map>
    #define N 200010
    using namespace std;
    typedef unsigned long long ull;
    struct data
    {
    	ull b[N] , h1[N] , h2[N];
    	ull hash(int l , int r)
    	{
    		return (h1[r] - h1[l - 1] * b[r - l + 1]) * (h2[l] - h2[r + 1] * b[r - l + 1]);
    	}
    }t1 , t2;
    map<pair<ull , ull> , bool> f;
    int a[N] , sta[N] , top;
    int main()
    {
    	int n , i , j , cnt , ans = 0;
    	scanf("%d" , &n);
    	t1.b[0] = t2.b[0] = 1;
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
    	for(i = 1 ; i <= n ; i ++ ) t1.b[i] = t1.b[i - 1] * 233 , t2.b[i] = t2.b[i - 1] * 2333;
    	for(i = 1 ; i <= n ; i ++ ) t1.h1[i] = t1.h1[i - 1] * 233 + a[i] , t2.h1[i] = t2.h1[i - 1] * 2333 + a[i];
    	for(i = n ; i >= 1 ; i -- ) t1.h2[i] = t1.h2[i + 1] * 233 + a[i] , t2.h2[i] = t2.h2[i + 1] * 2333 + a[i];
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		f.clear() , cnt = 0;
    		for(j = 1 ; j + i - 1 <= n ; j += i)
    			if(!f[make_pair(t1.hash(j , j + i - 1) , t2.hash(j , j + i - 1))])
    				f[make_pair(t1.hash(j , j + i - 1) , t2.hash(j , j + i - 1))] = 1 , cnt ++ ;
    		if(cnt > ans) top = 1 , sta[top] = i , ans = cnt;
    		else if(cnt == ans) sta[++top] = i;
    	}
    	printf("%d %d
    " , ans , top);
    	for(i = 1 ; i < top ; i ++ ) printf("%d " , sta[i]);
    	printf("%d" , sta[top]);
    	return 0;
    }
    

     

  • 相关阅读:
    TF-IDF
    智力题
    max{X,Y}和min{X,Y}的概率分布
    K-Means
    提高工作效率:给设计师的10条建议
    每个软件工程师都应该尝试的5件事
    CSS sprite 圆角——源代码
    比较大气的网页元素
    彩色网页变黑白色CSS代码变黑白色调!
    jquery适用技巧
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7061344.html
Copyright © 2020-2023  润新知