zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    BZOJ 1191 HNOI2006 超级英雄hero
    BZOJ 2442 Usaco2011 Open 修建草坪
    BZOJ 1812 IOI 2005 riv
    OJ 1159 holiday
    BZOJ 1491 NOI 2007 社交网络
    NOIP2014 D1 T3
    BZOJ 2423 HAOI 2010 最长公共子序列
    LCA模板
    NOIP 2015 D1T2信息传递
    数据结构
  • 原文地址:https://www.cnblogs.com/asdfsag/p/11704245.html
Copyright © 2011-2022 走看看