hdu4676 ——麥比烏斯反演&&分塊

來源:互聯網
上載者:User

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=4676

解題思路:總體上這是一個數學題加上離線與分塊處理加速。顯然對於區間內有公約數x的數來說,假設有num[x]個x的倍數,那麼答案顯然是sigma(C(num[x],2)*f(x)),根據容斥原理f(x)應該是一個小於x的數並且滿足sigma(f(d)) = x{d|x},因為有x這個約數的數對一定也有d這個約數,其中d|x,所以我在加上C(num[x],2)*f(x)之前就把C(num[d],2)*f(d)加上了,而總共對於x所需累加的次數是x,所以有sigma(f(d))
= x{d|x},而這正是麥比烏斯反演公式,可得f(d)為歐拉函數,http://www.isnowfy.com/mobius-inversion/

       然後每加入一個數我們只要加上num[x]*phi[x]就行了(根據組合公式的性質比較容易看出)。但是直接暴力的話複雜度會超,就是對於查詢區間大幅波動的情況就需要不停的加入點,刪除點,複雜度估計能達到n平方,所以我們採用離線查詢的方式,然後對查詢左端點分段排,在每一段內保證查詢右端點的有序性,這樣就可以大致保持查詢左端點和右端點的有序性。下面上代碼:


#include<cstdio>#include<iostream>#include<vector>#include<cmath>#include<cstring>#include<algorithm>#define N 20005using namespace std;int phi[N],a[N],num[N],ans[N];int L,R,ret;vector<int>d[N];struct node{    int l,r,id,s;}seg[N];void init(){    for(int i = 1;i<N;i++)phi[i] = i;    for(int i = 2;i<N;i++)        if(phi[i] == i)            for(int j = i;j<N;j+=i)                phi[j] = phi[j]/i*(i-1);    for(int i = 1;i<N;i++)        for(int j = i;j<N;j+=i)            d[j].push_back(i);}void Insert(int x){    for(int i = 0;i<d[x].size();i++)    {        int v = d[x][i];        ret+=num[v]*phi[v];        num[v]++;    }}void Delete(int x){    for(int i = 0;i<d[x].size();i++)    {        int v = d[x][i];        num[v]--;        ret-=num[v]*phi[v];    }}void query(int l,int r){    for(int i = l;i<L;i++)Insert(a[i]);    for(int i = L;i<l;i++)Delete(a[i]);    for(int i = r+1;i<=R;i++)Delete(a[i]);    for(int i = R+1;i<=r;i++)Insert(a[i]);}bool cmp(node x,node y){    if(x.s == y.s)return x.r<y.r;    return x.s<y.s;}int main(){    int t,y,n,m,i,j,cas = 1;    scanf("%d",&t);    init();    while(t--)    {        scanf("%d",&n);        int size = sqrt(1.0*n);        memset(num,0,sizeof(num));        for(i = 1;i<=n;i++)            scanf("%d",&a[i]);        scanf("%d",&m);        for(i = 1;i<=m;i++)        {            scanf("%d%d",&seg[i].l,&seg[i].r);            seg[i].id = i;            seg[i].s = seg[i].l/size;        }        sort(seg+1,seg+m+1,cmp);        ret = 0;        L = seg[1].l;        R = seg[1].r;        for(i = L;i<=R;i++)Insert(a[i]);        ans[seg[1].id] = ret;        for(i = 2;i<=m;i++)        {            query(seg[i].l,seg[i].r);            L = seg[i].l;            R = seg[i].r;            ans[seg[i].id] = ret;        }        printf("Case #%d:\n",cas++);        for(i=1;i<=m;i++)            printf("%d\n",ans[i]);    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.