bzoj4532: [BeiJing2014 WinterCamp] 珠链

我TM真是读题之神zzzzzzz 只能在头尾取啊233333

R-L+1这么小肯定是用来枚举的

然后那个约数个数是强行拼起来搞我的,弄那么多花里胡哨的东西很容易忽略什么,预处理一下就变成点权了

主要问题在符合规范,两两每个位置都不一样

容易发现每个位置放过一个字母以后就不能再放了,所以最多放52次

由于枚举了段的长度,那么可以把序列按对长度取模分组,只有相同组的有可能放在不同段的同一位置

考虑枚举起点,处理出最远能够不重复的终点,稍微计算一下里面的段数更新一下答案就好了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int _=1e2;
const int maxn=5*1e5+_;
int pr,prime[maxn],qc[maxn];bool pv[maxn];
LL yc[maxn]; 
void yu()
{
    pr=0;yc[1]=1;
    for(int i=2;i<maxn;i++)
    {
        if(pv[i]==false)
            prime[++pr]=i,yc[i]=2,qc[i]=1;
        for(int j=1;j<=pr&&i*prime[j]<maxn;j++)
        {
            pv[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                qc[i*prime[j]]=qc[i]+1;
                yc[i*prime[j]]=yc[i]/(qc[i]+1)*(qc[i]+2);
                break;
            }
            else 
            {
                qc[i*prime[j]]=1;
                yc[i*prime[j]]=yc[i]*2;
            }
        }
        yc[i]+=yc[i-1];
    }
}


int n,S,a[maxn];char ss[maxn];
bool b[maxn][60];
LL calc(int L)
{
    int st,ed=0; LL ret=0;
    for(st=1;st<=n;st++)
    {
        while(ed<n)
        {
            ed++;
            if(b[ed%L][a[ed]]==false)
                b[ed%L][a[ed]]=true;
            else {ed--;break;}
        }
        int u=(ed-st+1)/L;//段数
        if(u>=S)
        {
            u=st+L*u-1;//真正合法右界 
            ret=max(ret,yc[u]-yc[st-1]);
        }
        b[st%L][a[st]]=false;
    }
    while(st<=ed)b[st%L][a[st]]=false,st++;
    
    return ret;
}

int main()
{
    yu();
    int LLLL,RRRR;
    scanf("%d%d%d%d%s",&n,&LLLL,&RRRR,&S,ss+1);
    for(int i=1;i<=n;i++)
        if('a'<=ss[i]&&ss[i]<='z')a[i]=ss[i]-'a'+1;
        else a[i]=ss[i]-'A'+27;
    
    LL ans=0;
    for(int i=LLLL;i<=RRRR;i++)ans=max(ans,calc(i));
    if(ans==0)puts("-1");
    else printf("%lld
",ans);
    
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/10431349.html