1. 程式人生 > >[莫比烏斯反演] bzoj2301: [HAOI2011]Problem b

[莫比烏斯反演] bzoj2301: [HAOI2011]Problem b

因為不保證a,c=1 減掉1~a和1~d 1~c和1~b 的匹配 然後把重複的1~a和1~c的匹配加回來
然後就T掉了nice!

加一個分塊加速
因為有很大一段的(b/i) (d/i) 是一樣的
就相當於乘法分配率
U[ ]用上字首和之後 直接瞎跳小的那個就ok

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int prime[51000],mu[51000],pr;//mu:反演時的係數(容斥) 
bool v[110000];
void get_mu()
{
    memset
(v,1,sizeof(v)); mu[1]=1;mu[0]=0; for (int i=2;i<=50000;i++) { if (v[i]==true) { prime[++pr]=i; mu[i]=-1;//1個也是奇數個 } for(int j=1;j<=pr&&prime[j]*i<=50000;j++) { v[prime[j]*i]=0; if (i%prime[j]==0) { mu[i*prime[j]]=0
; //i包含了prime[j] e>1 break; } else { mu[i*prime[j]]=-mu[i];//奇變偶 偶變奇 } } mu[i]+=mu[i-1];//字首和 } } long long get(int a,int b) { long long ans=0; int next=0; int c=min(a,b); for (int i=1
;i<=c;i=next+1) { next=min(a/(a/i),b/(b/i)); ans+=(long long)(mu[next]-mu[i-1])*(a/i)*(b/i); } return ans; } int main() { //F(t)=gcd(x,y)%t==0 的x,y個數 =gcd(x,y) 的倍數的個數 F(6)=f(1)+f(2)+f(3)+f(6); //f(t)=gcd(x,y)=t 的x,y個數 = t的gcd個數 此時由f(t) 推回F(t) 這就是反演公式 F(t)=(b/t)*(b/t) //如果gcd(x,y)=1 gcd(x*k,,y*k)=k 直接除掉 k 然後求 f(1) 然後 x,y在1~b選的時候可能會有重(gcd(2,3)=gcd(3,2)) /2去重 get_mu(); int t; scanf("%d",&t); while (t--) { int a,b,c,d,k; scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); if (k==0) {printf("0\n");continue;} a=(a-1)/k;b/=k;c=(c-1)/k;d/=k;k=1; long long ans1=0,ans2=0,ans3=0,ans4=0,ans5=0; ans1=get(b,d); ans3=get(a,d);//1~a 和 1~d 匹配 ans4=get(c,b);//1~c 和 1~b 匹配 ans5=get(a,c);//1~a 和 1~c 匹配 printf("%lld\n",ans1-ans3-ans4+ans5); } return 0; }