CF1202F You Are Given Some Letters...
codeforces
有一个很显然的\(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<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
#define rg register
void 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<t||b<t)continue;
int al=a/(t+1)+(a%(t+1)!=0),ar=a/t;
int bl=b/(t+1)+(b%(t+1)!=0),br=b/t;
if(al<=ar&&bl<=br)ans+=max(0,min(j,ar+br)-max(i,al+bl)+1);
}
printf("%d\n",ans);
}