哈希 POI KOR-Beads

版权声明:未经本蒟蒻同意,请勿转载本蒻博客 https://blog.csdn.net/wddwjlss/article/details/83118068

题意: 给出 n n 个数,可将它们分为连续的若干个串,每个串有 k k 个数(长度不足 k k 则丢弃),如串 ( 1 , 1 , 1 , 2 , 2 , 2 , 3 , 3 , 3 , 1 , 2 , 3 , 3 , 1 , 2 , 2 , 1 , 3 , 3 , 2 , 1 ) (1,1,1,2,2,2,3,3,3,1,2,3,3,1,2,2,1,3,3,2,1) ,当 k = 2 k=2 时,我们得到 6 6 个不同的子串: ( 1 , 1 ) , ( 1 , 2 ) , ( 2 , 2 ) , ( 3 , 3 ) , ( 3 , 1 ) , ( 2 , 3 ) (1,1),(1,2),(2,2),(3,3),(3,1),(2,3) 。 求使得不同的串最多的 k k 值及串的个数。串可翻转,即子串 1 , 2 , 3 1,2,3 3 , 2 , 1 3,2,1 被认为是一样的。

我们预处理出前缀哈希和后缀哈希,这里我们自然溢出,对于枚举到的每一个k,我们求出每一段的前缀哈希和后缀哈希,然后将2者相乘用set判重。

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int c=2000001001;
int n,a[1001000],k;
ull hash1[1001000],mi[1001000],ans,res[1001000],maxn,hash2[1001000];
set<ull> s;
int main()
{
	mi[0]=1;
    cin>>n;
    for(int i=1;i<=n;++i)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;++i)
    {
        hash1[i]=hash1[i-1]*c+a[i];//前缀哈希
        mi[i]=mi[i-1]*c;
    }	
    for(int i=n;i>=1;--i)
    	hash2[i]=hash2[i+1]*c+a[i];//后缀哈希
    for(int i=1;i<=n;++i)//枚举题目中的k
    {
    	if(n/i<maxn)//对于当前的k如果可以分成的段数小于已经求出的最大值
			break;
    	s.clear();
        k=0;
        for(int j=i;j<=n;j+=i)//枚举每一段
        {
            ull g1=hash1[j]-hash1[j-i]*mi[i];//这一段的前缀哈希
            ull g2=hash2[j-i+1]-hash2[j+1]*mi[i];//这一段的后缀哈希
            ull g3=g1*g2;//将2者相乘放入set里
            if(s.count(g3))
            	continue;
            s.insert(g3);
            k++;
        }
        if(k>maxn)
        {
            ans=1;
            maxn=k;
            res[ans]=i;
        }
        else if(k==maxn)
        {
            ans++;
            res[ans]=i;

        }
    }
    cout<<maxn<<" "<<ans<<endl;
    for(int i=1;i<=ans;++i)
        printf("%d ",res[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wddwjlss/article/details/83118068
poi