题目描述
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; }