我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; }