1. 程式人生 > 其它 >21.6.23 t1

21.6.23 t1

tag:數論,杜教篩,類歐函式,莫比烏斯反演


改一下,求 \(\frac ij\le \frac ab\)

先莫反一下,方便求。

\[\sum_{gcd(i,j)=1}\frac ij\le\frac ab \]\[\sum_{d}\mu(d)\sum_{i=1}^{\left\lfloor\frac nd\right\rfloor}\sum_{j=1}^{\left\lfloor\frac nd\right\rfloor}\frac ij\le\frac ab \]

數論分塊,\(\mu\) 的字首和是杜教篩模板,後面一堆是類歐函式模板第一問。


注意一個坑點, \(10^{10}\times10^{10}\)

會爆long long。

#include<bits/stdc++.h>
using namespace std;
   
template<typename T>
inline void Read(T &n){
    char ch; bool flag=false;
    while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
    for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
    if(flag)n=-n;
}
   
typedef long long ll;
  
enum{
    MOD = 998244353,
    MAXN = 10000005,
    inv2 = MOD+1>>1
};
   
inline int inc(int a, int b){
    a += b;
    if(a>=MOD) a -= MOD;
    return a;
}
   
inline int dec(int a, int b){
    a -= b;
    if(a<0) a += MOD;
    return a;
}
   
inline void iinc(int &a, int b){a = inc(a,b);}
inline void ddec(int &a, int b){a = dec(a,b);}
inline void upd(int &a, ll b){a = (a+b)%MOD;}
   
namespace pts30{
    int gcd(int a, int b){return b?gcd(b,a%b):a;}
   
    inline int solve(int a, int b, int c, int d, int n){
        int ans=0;
        for(int i=1; i<=n; i++) for(int j=(1ll*a*i+b-1)/b; j<=1ll*c*i/d; j++) if(gcd(i,j)==1) ans++;
        return ans%MOD;
    }
}
   
char check[MAXN];
int mu[MAXN], prime[MAXN], pnum;
inline void sieve(){
    mu[1] = 1;
    for(int i=2; i<MAXN; i++){
        if(!check[i]) prime[++pnum] = i, mu[i] = -1;
        for(int j=1; i*prime[j]<MAXN and j<=pnum; j++){
            check[i*prime[j]] = true;
            if(i%prime[j]==0) break;
            mu[i*prime[j]] = -mu[i];
        }
    }
    for(int i=1; i<MAXN; i++){
        if(mu[i]==-1) mu[i] = MOD-1;
        iinc(mu[i],mu[i-1]);
    }
}
   
int count(ll a, ll b, ll c, ll n){
    if(a==0) return (n+1)%MOD*(b/c)%MOD;
    if(a>=c or b>=c) return (n%MOD*(n+1)%MOD*inv2%MOD*(a/c)+(n+1)%MOD*(b/c)+count(a%c,b%c,c,n))%MOD;
    ll m = (n*a+b)/c;
    return dec(n%MOD*m%MOD,count(c,c-b-1,a,m-1));
}
   
namespace Sieve{
    ll n, M;
   
    inline int id(ll x){return x<=M ? x : M+n/x;}
   
    char vis[MAXN<<1];
    int smu[MAXN<<1];
    int get_mu(ll x){
        if(x<MAXN) return mu[x];
        if(vis[id(x)]) return smu[id(x)];
        vis[id(x)] = true;
           
        int res=1;
        for(register ll l=2, r=0; l<=x; l=r+1){
            r = x/(x/l);
            ddec(res,(r-l+1)*get_mu(x/l)%MOD);
        }
           
        return smu[id(x)] = res;
    }
}
   
inline int summu(ll l, ll r){
    // return dec(mu[r],mu[l-1]);
    return dec(Sieve::get_mu(r),Sieve::get_mu(l-1));
}
   
inline int calc(int a, int b, ll n){
    int ans=0;
    for(ll l=1, r; l<=n; l=r+1){
        r = n/(n/l);
        upd(ans,1ll*summu(l,r)*count(a,0,b,n/l));
    }
    return ans;
}
   
inline int solve(int a, int b, int c, int d, ll n){return inc(dec(calc(c,d,n),calc(a,b,n)),d<=n);}
   
int main(){
    int T;
    Read(T); sieve();
    while(T--){
        ll n; int a, b, c, d;
        Read(n); Read(a); Read(b); Read(c); Read(d);
        Sieve::n = n; memset(Sieve::vis,0,sizeof Sieve::vis); Sieve::M = sqrt(n);
        // cout<<pts30::solve(a,b,c,d,n)<<'\n';
        cout<<solve(a,b,c,d,n)<<'\n';
    }
    return 0;
}