有一个很显然的\(O(a+b)\)的做法可以想到,就是枚举\(k\),然后\(O(1)\)判断
如何\(O(1)\)判断,我们显然考虑将这个序列每\(k\)个分一个块,只要判断存不存在合法方案就行了
其实这个时候很显然就能想到整除分块了,所以复杂度已经优化到\(O(\sqrt{a+b})\)了
判断的方法为:
我们需要满足每个块都能放满,并且每个块中\(\rm A\)和\(\rm B\)的数量相等
设\(n\)为总长度,\(m\)为完整的块数,\(s_a\)为每个块中的\(A\)的数量,\(s_b\)为每个块中\(B\)的数量
\[ n=a+b,m=\lfloor\frac{n}{k}\rfloor\\ s_a+s_b=k\\ s_a*m<=a,s_b*m<=b\\ s_a<=\lfloor\frac{a}{m}\rfloor,s_b<=\lfloor\frac{b}{m}\rfloor\\ a-s_a*m<=s_a,b-s_b*m<=s_b\\ s_a>=\lceil\frac{a}{m+1}\rceil,s_b>=\lceil\frac{b}{m+1}\rceil\\ \] 则\[ \lceil\frac{a}{m+1}\rceil<=s_a<=\lfloor\frac{a}{m}\rfloor\\\lceil\frac{b}{m+1}\rceil<=s_b<=\lfloor\frac{b}{m}\rfloor \] 然后计算有多少合法的\(k\)就好了代码:
#include#include #include using namespace std;#define rg registervoid read(int &x){ char ch;bool ok; for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1; for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;}const int maxn=1e5+10;int a,b,n,ans;int main(){ read(a),read(b);n=a+b; for(rg int i=1,j;i<=n;i=j+1){ j=n/(n/i);int t=n/i; if(a