hihocoder #1073 : 光棍節

描述node

儘管付出了種種努力,jzp仍是得過光棍節。ios

jzp很是不爽,但也無能爲力,只可以哀嘆起來他的命運。他想到了一位長者的人生經驗:「人的一輩子,不光要靠自我奮鬥,也要考慮歷史的進程」。數組

他終於明白本身只是時運不濟,因此又繼續開始努力。終於在聖誕節當天把到了妹子。app

jzp今後過上了快樂的現充生活,在聖誕節當天,他還和妹子玩起了有趣的遊戲:spa

jzp的家裏有一棵很是大的聖誕樹,能夠當作是一個n個點的無向聯通無環圖。每一個點上都有一個正整數,JZP和妹子每次都會選擇樹上的一條路徑,code

這條路徑的權值被定義爲路徑上全部點上數的最大公約數,JZP能夠獲得這個權值的分數。遊戲

JZP玩了一下子有點膩了,他想知道對於每種可能的權值x,權值爲x的不一樣路徑的數量(a到b的路徑和b到a的路徑算做一種,a到a自身也算做一條路徑。)進程

解題報告:
用時2h30min,N TLE
這題不難,直接暴力點分,複雜度能夠證實是對的,由於從一個點下去,gcd只有能夠是它的約數,因此是\(\sqrt n\)的,因此直接去重以後兩重循環枚舉,複雜度是\(O(n)\)的,因此複雜度是對的。可是本人太渣,點分均可以寫錯,找重心的數組一直沒清空(那麼竟然是0.7s是怎麼回事?)而後一交就TLE,還覺得是常數太大,就一直在壓,浪費了許久,寫了兩個代碼,一個是全部方案-不合法的,另外一個是用vector維護已經處理過的子樹的gcd,處理完當前子樹後,在處理另外一個子樹直接用當前子樹的每個gcd和vector裏的元素匹配.
get

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,val[N],head[N],num=0,nxt[N<<1],to[N<<1],sum;
void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
bool vis[N];int sz[N],root=0,son[N]={N};
il int gi(){
    RG int str=0;RG char ch=getchar();
    while(ch>'9' || ch<'0')ch=getchar();
    while(ch>='0' && ch<='9')
        str=(str<<1)+(str<<3)+ch-48,ch=getchar();
    return str;
}
il void getroot(int x,int last){
    int u;sz[x]=1;son[x]=0;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==last || vis[u])continue;
        getroot(u,x);
        sz[x]+=sz[u];son[x]=Max(son[x],sz[u]);
    }
    son[x]=Max(son[x],sum-sz[x]);
    if(son[x]<son[root])root=x;
}
il int gcd(int x,int y){
    int c;while(x%y){c=y;y=x%y;x=c;}
    return y;
}
vector<int>q,s;ll t[N],ton[N];
void count(int x){
    int szz=q.size(),gc;
    for(int i=0;i<szz;i++){
        gc=gcd(q[i],x);
        t[gc]+=ton[q[i]];
    }
}
int app[N];
il void calc(int x,int last,int g){
    int u;
    t[g]++;count(g);
    if(!app[g])s.push_back(g);app[g]++;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==last || vis[u])continue;
        if(g!=1)calc(u,x,gcd(val[u],g));
        else calc(u,x,1);
    }
}
il void solve(int x){
    int u,szz;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(vis[u])continue;
        calc(u,x,gcd(val[u],val[x]));
        szz=s.size();
        for(int j=0;j<szz;j++){
            if(!ton[s[j]])q.push_back(s[j]);
            ton[s[j]]+=app[s[j]];app[s[j]]=0;
        }
        s.clear();
    }szz=q.size();
    for(int i=0;i<szz;i++)ton[q[i]]=0;
    q.clear();
}
il void dfs(int x){
    int u;vis[x]=true;solve(x);
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(vis[u])continue;
        root=0;sum=sz[u];getroot(u,x);
        dfs(root);
    }
}
void work()
{
    int x,y,lim=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        val[i]=gi();
        lim=Max(lim,val[i]);
        t[val[i]]++;
    }
    for(int i=1;i<n;i++){
        x=gi();y=gi();
        link(x,y);link(y,x);
    }
    sum=n;root=0;getroot(1,1);
    dfs(root);
    for(int i=1;i<=lim;i++)
        if(t[i])printf("%d %lld\n",i,t[i]);
}

int main()
{
    work();
    return 0;
}

再是原來寫的,清空數組後也能過string

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,val[N],head[N],num=0,nxt[N<<1],to[N<<1],sum;
void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
bool vis[N];int sz[N],root=0,son[N]={N};
il int gi(){
    RG int str=0;RG char ch=getchar();
    while(ch>'9' || ch<'0')ch=getchar();
    while(ch>='0' && ch<='9')
        str=(str<<1)+(str<<3)+ch-48,ch=getchar();
    return str;
}
il void getroot(int x,int last){
    int u;sz[x]=1;son[x]=0;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==last || vis[u])continue;
        getroot(u,x);
        sz[x]+=sz[u];son[x]=Max(son[x],sz[u]);
    }
    son[x]=Max(son[x],sum-sz[x]);
    if(son[x]<son[root])root=x;
}
il int gcd(int x,int y){
    int c;while(x%y){c=y;y=x%y;x=c;}
    return y;
}
struct node{
    int x;ll cnt;
    bool operator <(const node &Pr)const{return x<Pr.x;}
}q[N];
int top=0;bool flag=false;
il void calc(int x,int last,int g){
    int u;
    if(g==1 && flag){q[++top].x=1;q[top].cnt=sz[x];return ;}
    if(top && q[top].x==g)q[top].cnt++;
    else q[++top].x=g,q[top].cnt=1;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(u==last || vis[u])continue;
        if(g!=1)calc(u,x,gcd(val[u],g));
        else calc(u,x,1);
    }
}
ll t[N];
il void solve(int x,int op,int sta){
    top=0;calc(x,x,sta);
    int Yut=top;top=1;
    sort(q+1,q+Yut+1);
    RG int i,j;
    for(i=2;i<=Yut;i++){
        if(q[i].x==q[top].x)q[top].cnt+=q[i].cnt;
        else q[++top]=q[i];
    }
    int tmp;
    for(i=1;i<=top;i++){
        t[q[i].x]+=q[i].cnt*(q[i].cnt-1)*op>>1;
        for(j=i+1;j<=top;j++){
            tmp=gcd(q[i].x,q[j].x);
            t[tmp]+=q[i].cnt*q[j].cnt*op;
        }
    }
}
il void dfs(int x){
    int u;vis[x]=true;
    flag=false;solve(x,1,val[x]);
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];if(vis[u])continue;
        root=0;sum=sz[u];getroot(u,x);
        flag=true;solve(u,-1,gcd(val[x],val[u]));
        dfs(root);
    }
}
void work()
{
    int x,y,lim=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        val[i]=gi();
        lim=Max(lim,val[i]);
        t[val[i]]++;
    }
    for(int i=1;i<n;i++){
        x=gi();y=gi();
        link(x,y);link(y,x);
    }
    sum=n;root=0;getroot(1,1);
    dfs(root);
    for(int i=1;i<=lim;i++)
        if(t[i])printf("%d %lld\n",i,t[i]);
}

int main()
{
    work();
    return 0;
}
相關文章
相關標籤/搜索