• CodeForces


    题意:一个字符串包含a个A和b个B,求这个字符串所有可能的循环节长度(末尾可能存在不完整的循环节)

    好题,但思路不是很好想。

    首先由于循环节长度可以任意取,而循环次数最多只有$O(sqrt n)$个,因此考虑枚举循环次数(利用整除分块的思想),求a,b可能的循环长度。

    那么问题转化成了:给定最大循环次数k和字符个数n,求循环长度l的取值范围,也就是使得$left lfloor frac{n}{l} ight floor=k$的l的取值范围。

    首先确定l的上界,即$klleqslant n$,$lleqslant left lfloor frac{n}{k} ight floor$,这个是显然的。

    然后确定l的下界,如果$kl+lleqslant n$的话,那么可以再分出去一个l,与最大循环次数为k矛盾,因此下界为$(k+1)l>n$,$lgeqslantleft lfloor frac{n}{k+1} ight floor+1$。

    综上,l的取值范围应为$[left lfloor frac{n}{k+1} ight floor+1,left lfloor frac{n}{k} ight floor]$。

    然后貌似对于每个最大循环次数k,令n分别等于a,b,求出a和b的取值范围,进而确定a+b的取值范围就可以了。

    但是这里有一个问题:a和b的k值不一定相等!比如说有10个a,9个b,每段有2个a和2个b,那么a和b的k值分别为5和4!(坑死人)

    于是只能允许$kl+l=n$的情况存在了,也就是强行令$(k+1)lgeqslant n$,即$lgeqslant left lceil frac{n}{k+1} ight ceil=left lfloor frac{n+k}{k+1} ight floor$,这样就能应付上面的特殊情况了。

    然而这样还没完,求出的取值范围可能有重复!怎样去重呢?最无脑的方法是把所有取值范围的区间排个序然后从左往右扫一遍,不过也可以限制一下l的取值范围,也就是强行令$lin [left lfloor frac{a+b}{k+1} ight floor+1,left lfloor frac{a+b}{k} ight floor]$,这样就能避免重复了。

    逻辑可能不是很清晰,如果还不明白的话可以去看官方题解

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N=1e5+10,inf=0x3f3f3f3f;
     5 int a,b;
     6 int main() {
     7     scanf("%d%d",&a,&b);
     8     int ans=0;
     9     for(int l=1,r,k; l<=a+b; l=r+1) {
    10         k=(a+b)/l,r=(a+b)/k;
    11         int L1=(a+k)/(k+1),R1=a/k;
    12         int L2=(b+k)/(k+1),R2=b/k;
    13         if(L1<=R1&&L2<=R2)ans+=min(R1+R2,r)-max(L1+L2,l)+1;
    14     }
    15     printf("%d
    ",ans);
    16     return 0;
    17 }
  • 相关阅读:
    poj 3415 后缀数组+单调栈
    hdu 3450 后缀数组
    hdu 2774 后缀数组
    后缀数组模板(倍增法)
    hdu 4405 概率dp
    zoj 3329 概率dp
    [日常摸鱼]bzoj2875[NOI2012]随机数生成器-矩阵快速幂
    [日常摸鱼]bzoj1038[ZJOI2008]瞭望塔-半平面交
    [日常摸鱼]bzoj1007[HNOI2008]水平可见直线-半平面交(对偶转凸包)
    [日常摸鱼]bzoj3083遥远的国度-树链剖分
  • 原文地址:https://www.cnblogs.com/asdfsag/p/11704245.html
Copyright © 2020-2023  润新知