zoukankan      html  css  js  c++  java
  • bzoj3309 DZY Loves Math

    bzoj3309


    前戏

    ai=1bj=1f(gcd(i,j))
    =ad=1ai=1bj=1e(gcd(i,j)==d)f(d)
    =ad=1a/di=1b/dj=1e(gcd(i,j)==1)f(d)
    =ad=1a/di=1b/dj=1d|id|jμ(d)f(d)
    =ad=1f(d)a/dd=1μ(d)a/ddi=1b/ddj=11
    =ad=1f(d)a/dd=1μ(d)addbdd
    考虑枚举dd’
    =ai=1aibid|if(d)μ(i/d)
    很显然f虽然不是积性函数但是可以被筛出来,
    对于后面一部分g(i)=d|if(d)μ(i/d)我一开始是准备埃氏筛法,但是时限太紧了TAT
    然而这玩意儿一副欧拉筛不可做的样子。

    解决

    然后我们就可以发现我们是不用考虑mu值等于0的那一部分。
    考虑i=qr11qr22qrtt假设其中rw最大且一共有k个r是与rw相等的.
    很显然,对于我们考虑的μ(d),d是{q1,q2,qn}这个集合的一个子集内所有元素相乘的一个值.
    我们可以将这些子集按包不包含元素rw来分成两两一组(也就是说每一组除去rw都应该是一样的),假设除去rw后集合为T如果j,rjT那么显然他们对应的f值是相等的,也就是说这一对对g(i)的贡献相加=0.
    所以我们应该考虑的是所有包含了这k个元素的集合,那么最后的答案应该是
    t1i=k1Ci(k1)t1(k1)(1)i+1(ans+1)Ci(k1)t1(k1)(1)ians
    =t1i=k1Ci(k1)t1(k1)(1)i=tki=0Citk(1)i+k1
    t=k时,原式=(1)k+1
    tk时,根据二项式定理,原式=(1+1)tk=0
    所以我们如果能统计出每个数对应的t和k就搞定辣,这个很好筛出来的.
    发现标程有辣么短,自己好长QAQ

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<ctime>
    const int N = 1e7 + 7;
    
    typedef long long ll;
    bool vis[N];
    int prime[N], tot, wor[N], wor2[N], sl[N], num[N], jx[N];
    
    void G (int &num) {
        static char a;
        for (a = getchar (); a > '9' || a < '0'; a = getchar ()) ;
        for (num = 0; a >= '0' && a <= '9'; a = getchar ()) num = (num << 3) + (num << 1) + a - '0';
    }
    
    void Pre () {
        vis[1] = true;
        for (int i = 2; i <= 10000000; ++i) {
            if (!vis[i]) prime[++tot] = i, wor[i] = wor2[i] = sl[i] = num[i] = 1;
            for (int j = 1; j <= tot && 1ll * i * prime[j] <= 10000000; ++j) {
                vis[i * prime[j]] = true;
                if (i % prime[j] == 0) {
                    sl[i * prime[j]] = sl[i] + 1;
                    wor[i * prime[j]] = wor[i];
                    if (sl[i * prime[j]] == wor2[i]) num[i * prime[j]] = num[i] + 1, wor2[i * prime[j]] = wor2[i]; 
                    else if (sl[i * prime[j]] > wor2[i]) num[i * prime[j]] = 1, wor2[i * prime[j]] = sl[i * prime[j]];
                    else num[i * prime[j]] = num[i], wor2[i * prime[j]] = wor2[i];
                    break;
                }
                sl[i * prime[j]] = 1;
                wor[i * prime[j]] = wor[i] + 1;
                wor2[i * prime[j]] = wor2[i];
                num[i * prime[j]] = num[i];
                if (wor2[i] == 1) ++num[i * prime[j]];
            }
            jx[i] = jx[i - 1];
            if (wor[i] == num[i]) jx[i] += num[i] & 1 ? 1 : -1;
        }
    }
    
    ll calc (int a, int b) {
        ll ret = 0;
        for (int i = 1, lo = 1; i <= a; i = lo + 1) {
            lo = std :: min (a / (a / i), b / (b / i));
            ret += 1ll * (jx[lo] - jx[i - 1]) * (a / i) * (b / i);
        }
        return ret;
    }
    
    void Solve () {
        int T, a, b;
        G (T);
        while (T--) {
            G (a), G (b);
            if (a > b) a ^= b ^= a ^= b;
            printf ("%lld
    ", calc (a, b));
        }
    }
    
    void IO () {
        freopen ("3309.in", "r", stdin);
        freopen ("3309.ans", "w", stdout);
    }
    
    int main () {
        IO ();
        Pre ();
        Solve ();
        return 0;
    }

    update :
    看了别人的代码,仔细研究了一番,发现我的信息记得过于全面,还是有很多玩意儿是可以省略的,现在附上简洁版的代码

    /**************
    +1
    written by DraZxlNDdt
    Accepted
    ***************/ 
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<ctime>
    const int N = 1e7 + 7;
    
    typedef long long ll;
    bool vis[N];
    int prime[N], tot, sl[N], jx[N], zx[N], g[N];
    
    void G (int &num) {
        static char a;
        for (a = getchar (); a > '9' || a < '0'; a = getchar ()) ;
        for (num = 0; a >= '0' && a <= '9'; a = getchar ()) num = (num << 3) + (num << 1) + a - '0';
    }
    
    void Pre () {
        vis[1] = true;
        for (int i = 2; i <= 10000000; ++i) {
            if (!vis[i]) prime[++tot] = i, zx[i] = i, sl[i] = g[i] = 1;
            for (int j = 1; j <= tot && 1ll * i * prime[j] <= 10000000; ++j) {
                vis[i * prime[j]] = true;
                if (i % prime[j] == 0) {
                    sl[i * prime[j]] = sl[i] + 1;
                    zx[i * prime[j]] = zx[i] * prime[j];
                    if (i == zx[i]) g[i * prime[j]] = 1;
                    else g[i * prime[j]] = sl[i * prime[j]] == sl[i / zx[i]] ? -g[i / zx[i]] : 0;
                    break;
                }
                sl[i * prime[j]] = 1;
                zx[i * prime[j]] = prime[j];
                g[i * prime[j]] = sl[i] == 1 ? -g[i] : 0;
            }
            jx[i] = jx[i - 1];
            if (g[i]) jx[i] += g[i];
        }
    }
    
    ll calc (int a, int b) {
        ll ret = 0;
        for (int i = 1, lo = 1; i <= a; i = lo + 1) {
            lo = std :: min (a / (a / i), b / (b / i));
            ret += 1ll * (jx[lo] - jx[i - 1]) * (a / i) * (b / i);
        }
        return ret;
    }
    
    void Solve () {
        int T, a, b;
        G (T);
        while (T--) {
            G (a), G (b);
            if (a > b) a ^= b ^= a ^= b;
            printf ("%lld
    ", calc (a, b));
        }
    }
    
    void IO () {
        freopen ("3309.in", "r", stdin);
        freopen ("3309.ans", "w", stdout);
    }
    
    int main () {
    //  IO ();
        Pre ();
        Solve ();
        return 0;
    }
  • 相关阅读:
    Ant编译android程序
    android系统短信库的一些用法
    Android APK 签名机制
    android调用照相机拍照获取照片并做简单剪裁
    调用Android系统“应用程序信息(Application Info)”界面
    Speex manul中文版
    Android amr语音编解码解惑
    android Notification 的使用
    ContentProvider和Uri详解
    深入理解SetUID
  • 原文地址:https://www.cnblogs.com/dcoi-king/p/7491425.html
Copyright © 2011-2022 走看看