P3498 [POI2010]KOR-Beads

题目描述

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代表珠子的长度,(),第二行是由空格分开的颜色ai(1<=ai<=n)。

输出格式:

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

输入输出样例

输入样例#1:

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

输出样例#1:

6 1
2

题解:

枚举长度+哈希

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
using namespace std;
const int maxn=200000+5;
const int B=200191;
typedef unsigned long long ull;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘) f=-1; ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
ull mul[maxn],s1[maxn],s2[maxn];
int n,mx,num;
int a[maxn],b[maxn];
gp_hash_table<ull,bool>mp;
ull gethash(int l,int r)
{
    ull t;
    if(l<=r) t=s1[r]-s1[l-1]*mul[r-l+1];
    else
    t=s2[r]-s2[l+1]*mul[l-r+1];
    return t;
}
void solve(int x)
{
    if(mx*x>n) return;
    int ans=0;
    mp.clear();
    for(int i=1;i<=n;i+=x)
    if(i+x-1<=n)
    {
        ull t=gethash(i,i+x-1)*gethash(i+x-1,i);
        if(mp[t]) continue;
        else ans++;
        mp[t]=1;
    }
    if(ans>mx) mx=ans,num=0;
    if(ans==mx) b[++num]=x;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    mul[0]=1;
    for(int i=1;i<=n;i++) mul[i]=mul[i-1]*B;
    for(int i=1;i<=n;i++)
        s1[i]=s1[i-1]*B+a[i];
    for(int i=n;i>=1;i--)
        s2[i]=s2[i+1]*B+a[i];
    for(int i=1;i<=n;i++) solve(i);
    printf("%d %d\n",mx,num);
    for(int i=1;i<=num;i++)
    {
        printf("%d",b[i]);
        if(i!=num) printf(" ");
    }
    return 0;
}
    
时间: 2024-10-14 04:40:40

P3498 [POI2010]KOR-Beads的相关文章

BZOJ2081 [Poi2010]Beads

我们只要暴力枚举块的大小就可以了... 枚举的总复杂度是O(n / 1 + n / 2 + n / 3 + ...) = O(n * logn)的 何如去重呢...直接暴力hash再丢进set里搞定,总复杂度O(n * log2n) 1 /************************************************************** 2 Problem: 2081 3 User: rausen 4 Language: C++ 5 Result: Accepted 6

【bzoj2081】[Poi2010]Beads Hash

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

BZOJ 2801 Poi2010 Beads Hash

题目大意:给定一个数字串,求所有的k满足当将这个数字串从左到右分成大小为k的块时不同的块数量最多 反转同构算一种 枚举k,对于每个k将不同的串插入哈希表去重 反转同构啥的每个串的哈希值乘一下反串的哈希值就行了 时间复杂度O(n/1+n/2+...+n/n)=O(nlogn) #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 20020

【BZOJ2081】【Poi2010(17th)】Beads RKhash+hash表 请记住这个神一样的数:200019

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45743869"); } 题解: 枚举串长,数据范围20W. 然后串长为 i 时需要枚举 ?ni? 次. 加一起是 O(nlogn) 我们把每个串hash一下就好了. 然后自然溢出就好了,,,. 我无限WA啊..最后wyfcyx给我提

单调队列 BZOJ 2096 [Poi2010]Pilots

2096: [Poi2010]Pilots Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 819  Solved: 418[Submit][Status][Discuss] Description Tz又耍畸形了!!他要当飞行员,他拿到了一个飞行员测试难度序列,他设定了一个难度差的最大值,在序列中他想找到一个最长的子串,任意两个难度差不会超过他设定的最大值.耍畸形一个人是不行的,于是他找到了你. Input 输入:第一行两个有空格隔开的整数k(0

BZOJ 2086: [Poi2010]Blocks

2086: [Poi2010]Blocks Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 494  Solved: 222[Submit][Status][Discuss] Description 给出N个正整数a[1..N],再给出一个正整数k,现在可以进行如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1.经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数

BZOJ 2080: [Poi2010]Railway 双栈排序

2080: [Poi2010]Railway Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 140  Solved: 35[Submit][Status][Discuss] Description 一个铁路包含两个侧线1和2,右边由A进入,左边由B出去(看下面的图片) 有n个车厢在通道A上,编号为1到n,它们被安排按照要求的顺序(a1,a2,a3,a4....an)进入侧线,进去还要出来,它们要按照编号顺序(1,2,3,4,5....n)从通道B

UVALive 5545 Glass Beads

Glass Beads Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Original ID: 554564-bit integer IO format: %lld      Java class name: Main Once upon a time there was a famous actress. As you may expect, she played mostly

BZOJ2086: [Poi2010]Blocks

题解: 想了想发现只需要求出最长的一段平均值>k即可. 平均值的问题给每个数减去k,判断是否连续的一段>0即可. 然后我们发现如果i<j 且 s[i]<s[j],那么 j 对于l>j不会比i 优. 那我们就可以维护一个单调的s[i],然后对于每个l去二分出它的答案. 但这样会T. 再次考虑单调性. 如果 l>j,且s[l]>s[i],那么我们的答案最小也是l-i,所以j必须取比i小的s才有可能更新答案.然后就可以两个指针扫一遍了. 好吧 我承认我口胡... 代码: