HDU 6134 Battlestation Operational (mobius +前缀和)

题目链接

Battlestation Operational

计算

f(n)=i=1nj=1iij[(i,j)=1]

分析

赛后看q神给了个简洁的题解才发现,自己走错方向了,计算前缀和要简单的多啊…


g(i)=j=1iijh(i)=j=1iij[(i,j)=1]

那么对 g 我们可以用 O(nlog) 用前缀和求出具体来说,对于一个固定的 j 他对它的倍数产生的累加是一样的,即
g(j)+=1,g(j+1,...,2j)+=2,...

然后我们看这个 h ,将后面的 艾弗森括号用mobius直接展开,

h(i)=j=1iij[(i,j)=1]=j=1iijd|(i,j)μ(d)=d|iμ(d)g(i/d)=d|iμ(i/d)g(d)

O(nlog(n)) 求出 h ,前缀和就是 f

留个截图纪念
HDU 6134 Battlestation Operational (mobius +前缀和)_第1张图片

AC code

/*
*Problem : 6134 ( Battlestation Operational )     Judge Status : Accepted
*RunId : 21783390    Language : G++    Author : zouzhitao
*Code Render Status : Rendered By HDOJ G++ Code Render Version 0.01 Beta
*/
#include
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
#define scint(x) scanf("%d",&x );
#define scf(x) scanf("%lf",&x );
#define eps 1e-10
#define dcmp(x) (fabs(x) < eps? 0:((x) <0?-1:1))
#define lc o<<1
#define rc o<<1|1
using namespace std;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> Pair;
const int maxn = 1e6+10;
const int MAX_V= 500+10;
const int MOD = 1e9+7;
LL mu[maxn],prime[maxn],cnt;
void mobius(){
    cnt =0;
    mu[1] = 1;
    memset(prime,0,sizeof(prime));
    for(int i = 2 ; iif(!prime[i]){
            prime[cnt++] = i;
            mu[i] =-1;
        }
        for(int j=0 ; j1;
            if(i%prime[j])mu[prime[j]*i] = -mu[i];
            else {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
}
LL g[maxn],h[maxn];
void init(){
    ms(g,0);
    ms(h,0);
    for(int j=1 ; jfor(int i = j ; i1]++;
    }
    for(int i=1 ; i1];g[i]%=MOD;}
    //for(int i=1 ; i<=10 ; ++i)std::cout << g[i] << '\n';
    for(int i=1 ; ifor(int j = i ; jfor(int i=1 ; i1];h[i]%=MOD;}
}
int main()
{
    // ios_base::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    mobius();
    init();
    int n;
    while (scanf("%d",&n )!=EOF) {
        printf("%d\n",h[n]);
    }



    return 0;
}

你可能感兴趣的:(算法刷题)