【url】http://www.zybbs.org/JudgeOnline/problem.php?id=1101
【题目大意】没法大意了- -,直接原题吧。
【算法】
直接暴力容斥可以在O(min(a,b))时间复杂度内解决一个询问。
先a/=d,b/=d
答案为Sum(d[i]*(a/i)*(b/i)),2<=i<=a其中d[i]是容斥系数。
那么可知a/i只有sqrt(a)级别种结果。b/i也只有sqrt(b)级别种结果。
也就是说随着i的递增,a/i和b/i总的变化数是sqrt(a)+sqrt(b)级别的。
于是对于a/i和b/i相同的放一组。一共只会有sqrt(a)+sqrt(b)级别组。通过对d构建前缀和数组可以做到O(1)处理每一组。
然后就没了。
【其它】
作为AC的门徒、外加NOI2010囧人,此题不切说不过去- –
【CODE】
#include
#include
const int N=50005;
int d[N];
int S[N];
bool prime[N];
void predo(){
memset(prime,true,sizeof(prime));
for (int i=2;i<=50000;i++) d[i]=1;
for (int i=2;i<=50000;i++)
if (prime[i]){
for (int j=i+i;j<=50000;j+=i){
prime[j]=false;
if (j/i%i==0) d[j]=0;
d[j]=-d[j];
}
d[i]=-1;
}
S[1]=0;
for (int i=2;i<=50000;i++) S[i]=S[i-1]+d[i];
}
void swap(int &x,int &y){
int t=x;
x=y;
y=t;
}
int min(int x,int y){return x
int Get_Next(int a,int b){ // let ret=a/b this function get the smallest number x satisfy a/x!=ret && x>b
return a/(a/b)+1;
}
int main(){
predo();
int Tc;
scanf("%d",&Tc);
while (Tc–){
int m,n,dd;
scanf("%d%d%d",&m,&n,&dd);
m/=dd;
n/=dd;
long long ans=(long long)m*n;
if (m>n) swap(m,n);
for (int i=2;i<=m;){
int Next=min(Get_Next(m,i),Get_Next(n,i));
long long tmp=(long long)(m/i)*(n/i);
ans+=(S[Next-1]-S[i-1])*tmp;
i=Next;
}
printf("%lldn",ans);
}
}
NOI的时候完全懒得写啊。……
回复ftiasch:……NOI的时候神马都不会
以后我就用这个表情回复cwj神牛的所有题目
最近准备搞组合,学习学习