bzoj3529 sdoi2014 数表

比较经典的一道数论题,听zky讲的,我太弱了,,,我这种懒人是在受不了在markdown里写,让map给我写吧
重点:1.数组小心越界,循环的时候最好用数据而不是自己估计的最大上界
2.注意想好了再写,多试试对不对,犯了一个非常严重的错误就是以为F(n)(约数和)函数可以O(N)线性筛,,,其实是不可以的,要算必须记录一大坨多余数据,,没得做,就暴力筛吧,复杂度O(NLOGN)还是可以接受的嘛,,,(对着黄学长标程拍了半天错了半天才明白)也就是说,求积性函数可以快速线性筛也可以暴力筛但暴力明显可以维护更多信息可以有更多变化,可以看到,越暴力的做法它的普适性越强对吧,,这种思想贯穿了整个oi,,,
3.注意有若干询问的时候考虑离线,有a的限制,我们可以用树状数组维护前缀和
公式:
i=1nj=1mσ(gcd(i,j))[gcd(i,j)a]
=k=1min(n,m)[nk][mk]d|kμ(kd)σ(d)
代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#define N1 20002
#define N2 100005
using namespace std;
struct data{ int x,y,w,num,ans;};
struct node{ int w,num;};
data e[N1]; 
node rou1[N2];
bool not_prime[N2];
int  q,prime[N2],mu[N2],t,c[N2],rou[N2],maxi;
bool cmp1(data a,data b){ return (a.w<b.w);}
bool cmp2(data a,data b){ return (a.num<b.num);}
bool cmp3(node a,node b){ return (a.w<b.w);}
int lowbit(int x){ return (x&(-x));}
void add(int s,int x){ for (int k=s;k<=N2;k+=lowbit(k)) c[k]+=x;}
void init(){
    scanf("%d",&q);
    for (int i=1;i<=q;++i) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
    for (int i=1;i<=q;++i) e[i].num=i;
    for (int i=1;i<=q;++i) if (e[i].x>e[i].y) swap(e[i].x,e[i].y);
    maxi=0;
    sort(e+1,e+q+1,cmp1);
    t=1; c[0]=0;
    for (int i=1;i<=q;++i) maxi=max(maxi,e[i].x);
    memset(c,0,sizeof(c));
}

void shai(){
    int tot=0;
    memset(not_prime,0,sizeof(not_prime));
    memset(rou1,0,sizeof(rou1));
    mu[1]=1; 
    for (int i=1;i<=maxi;++i) rou1[i].num=i;
    for (int i=2;i<=maxi;++i){
        if (!not_prime[i]) { prime[++tot]=i; mu[i]=-1;}
        for (int j=1;j<=tot;++j)
          if (prime[j]*i>maxi) break;
          else{  not_prime[prime[j]*i]=1;
            if (!(i%prime[j])) { mu[i*prime[j]]=0; }
            else { mu[i*prime[j]]=-mu[i];  }
          }
    }
    for (int i=1;i<=maxi;++i)
      for (int j=i;j<=maxi;j+=i) rou1[j].w+=i;
    sort(rou1+1,rou1+maxi+1,cmp3);
}

int query(int s){
    int sum=0;
    for (int k=s;k;k-=lowbit(k)) sum+=c[k];
    return sum;
}

int DO_it(int n,int m,int a){
    int sum=0;
    for (;rou1[t].w<=a&&t<=maxi;++t) 
      for (int j=1;j<=maxi/rou1[t].num;++j) add(j*rou1[t].num,rou1[t].w*mu[j]);
    for (int j=1,k=0;j<=n;j=k+1){
        k=min(n/(n/j),m/(m/j));
        sum+=(query(k)-query(j-1))*(n/j)*(m/j);
    }
    return sum;
}

void print(){
    sort(e+1,e+q+1,cmp2);
    for (int i=1;i<=q;++i) printf("%d\n",e[i].ans&0x7fffffff);
}

int main(){
    init();
    shai();
    for (int i=1;i<=q;++i) e[i].ans=DO_it(e[i].x,e[i].y,e[i].w);
    print();
    return 0;
}

你可能感兴趣的:(bzoj3529 sdoi2014 数表)