codeforces
有一个很显然的(O(a+b))的做法可以想到,就是枚举(k),然后(O(1))判断
如何(O(1))判断,我们显然考虑将这个序列每(k)个分一个块,只要判断存不存在合法方案就行了
其实这个时候很显然就能想到整除分块了,所以复杂度已经优化到(O(sqrt{a+b}))了
判断的方法为:
我们需要满足每个块都能放满,并且每个块中( m A)和( m B)的数量相等
设(n)为总长度,(m)为完整的块数,(s_a)为每个块中的(A)的数量,(s_b)为每个块中(B)的数量
[n=a+b,m=lfloorfrac{n}{k}
floor\
s_a+s_b=k\
s_a*m<=a,s_b*m<=b\
s_a<=lfloorfrac{a}{m}
floor,s_b<=lfloorfrac{b}{m}
floor\
a-s_a*m<=s_a,b-s_b*m<=s_b\
s_a>=lceilfrac{a}{m+1}
ceil,s_b>=lceilfrac{b}{m+1}
ceil\
]
则
[lceilfrac{a}{m+1}
ceil<=s_a<=lfloorfrac{a}{m}
floor\lceilfrac{b}{m+1}
ceil<=s_b<=lfloorfrac{b}{m}
floor
]
然后计算有多少合法的(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
",ans);
}