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);
}
posted @ 2019-08-23 17:08  蒟蒻--lichenxi  阅读(325)  评论(3编辑  收藏  举报