B题意:
两个篮子,左边M个饼干,右边N个饼干。
Alice先拿。Bob后拿。
拿的要求:假设选左边篮子,则拿k(k>0),要求M-K是M的正因数。
谁最后面对两个篮子都是1个饼干谁输。
现在有个人想让Alice必赢。他最多可以从左边去掉X个饼干,从右边去掉Y个饼干。
问: 0<=x<=X,0<=y<=Y的去掉中,满足要求的(x,y)有多少个[去掉后初始态为M-x和N-y]
思路:
1 1---》A输
两个质数-->A输
一质一和-->A赢
两合----1.因数数量存在不一致时,A赢 2.因数数量一致时,B赢
前三个状态都好理解。对于最后一个状态说明一下:当不一致的时候,谁先沉不住气或者能分解的情况没了,谁就输了。
比如M很大,N很小,那么A取M,B取N;A慢慢耗,B如果没了,或者一下跳到A给A拿完,那么A可以一下全拿完让自己获胜。
到了这一步之后我们看M-K。
既然你M-K 是M的因数,换言之,K就是M的一部分质因数分解的形式。(直接把其看成质因子分解形式,如果可以整除,K一定是其分解形式的一部分)
然后我们就先预处理一个筛,取一定范围内的每个数的质因子个数。统计相同质因数个数的情况,减去这个情况就好了。
注意卡常
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<unordered_map>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=5e6+100;
typedef long long LL;
int primes[maxn],v[maxn],m;///最小因子,质数数量
unordered_map<LL,LL>map1;
LL a[maxn];
///卡常严重,除了必要的其他全改int,同时考虑read(),unordered_map代替map
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void getprimes(int n){
for(int i=2;i<=n;i++){
if(v[i]==0){v[i]=i;primes[++m]=i;}
for(int j=1;j<=m;j++){
if(primes[j]>v[i]||primes[j]>n/i) break;
v[i*primes[j]]=primes[j];
}
}
}
void check(int x){
int temp=x;
for(int i=1;i<=m;i++){
if(primes[i]*primes[i]>x) break;
if(x%primes[i]==0){
while(x%primes[i]==0){
x/=primes[i];
a[temp]++;
}
}
}
if(x>1) a[temp]++;
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
getprimes(5000);
LL m,n,x,y;m=read();n=read();x=read();y=read();
for(int i=min(m-x,n-y);i<=max(m,n);i++){
check(i);///获得每个数的质因子总个数
}
LL ans=(x+1)*(y+1);
for(int i=m-x;i<=m;i++){
map1[a[i]]++;
}
for(int i=n-y;i<=n;i++){
ans-=map1[a[i]];
}
printf("%lld\n",ans);
return 0;
}