hdu 4670 点分治 + 哈希

这场比赛是我和杰哥两个人搞的,搞了三个小时才做两个题,几何题感觉有点思路,但最近做的不多,就懒得搞,最后想了想,反正队友搞不出其他题,自己艹出一个做的比较少的题娱乐一下吧,瞄了瞄做的比较少的题,1005,求合法点对的数量,这种题一眼题啊,分治 + 统计,XWLJ了,稍微推了下calc的过程,中间统计的时候一开始想用map,然后杰哥说可能爆吧,然后由于是比赛的后半期,也就懒得想,开了个哈希表就开始写了,巴拉巴拉敲了40分钟,在比赛结束的时候交了一发,显然无果。

但随后。。。。

发现可以用一个long long保存一个节点的30个信息,这样就避免了哈希表每次的初始化(这里坨坨要超时啊),直接用map也会很快,如果比赛的时候敲得就是map,早就AC了、、、、、好水啊,题水,人更水。。。。

还是贴个代码吧,很多注释都没去,懒得去了,我还是去做做点分治+FFT吧。。sad。。。。

/* **********************************************
Author      : wuyiqi
Created Time: 2013-8-13 11:34:59
File Name   : Cube number on a tree.cpp
*********************************************** */
#include<cstdio>  
#include<cstring>  
#include<vector>  
#include<map>
#include<algorithm>  
using namespace std;  
typedef __int64 lld;
const int maxn = 50010;  
lld val[maxn];
int in[maxn][33];
int pri[33];
int K;
int n;
int head[maxn];
int nxt[maxn*2];
int pnt[maxn*2];
int E ;
void add(int a,int b){
    pnt[E] = b;
    nxt[E] = head[a];
    head[a] = E++;
}
const int H = 100007;
struct Hash_table{
    int head[H];
    int nxt[maxn*2];
    int cnt[maxn*2];
    int biao[maxn*2][33];
    int E;
    void init() {
        E = 0;
        memset(head,-1,sizeof(head));
    }
    int find(lld num,int x[],bool flag) {
        int h = num % H;
        for(int i = head[h]; i != -1; i = nxt[i]) {
                bool f = true;
                for(int j = 0; j < K; j++) {
                        if(biao[i][j] != x[j]) {
                            f = false;
                            break;
                        }
                }
                if(f){
                     int ans = cnt[i];
                     if(flag) cnt[i] ++;
                     return ans;
                } 
         }
        if(flag) {
            cnt[E] = 1;
            for(int i = 0; i < K; i++) biao[E][i] = x[i];
            nxt[E] = head[h];
            head[h] = E++;
        }
        return 0;
    }
}ta;
struct fenzhi {
    bool Del[maxn];
    int size[maxn];
    int opt[maxn];
    int tnode[maxn] , tns;
    int all[maxn][33],as;
    int ID[maxn];
    void Dfs(int u,int f) {
        tnode[tns++] = u;
        size[u] = 1;
        opt[u] = 0;
        for(int i = head[u]; i != -1; i = nxt[i]) {
            int v = pnt[i];
            if(!Del[v] && v != f) {
                Dfs(v,u);
                size[u] += size[v];
                opt[u] = max(opt[u],size[v]);
            }
        }
    }
    int Get_Root(int u){
        tns = 0;
        Dfs(u,-1);
        int mi = maxn , ans = -1;
        for(int i = 0; i < tns; i++) {
            opt[tnode[i]] = max(opt[tnode[i]],size[u]-size[tnode[i]]);
            if(opt[tnode[i]] < mi) {
                mi = opt[tnode[i]];
                ans = tnode[i];
            }
        }
        return ans;
    }
    void Get_Dis(int u,int fa){
      //  printf("u=%d\n",u);
        int fid ;
        if(fa != -1) {
            fid = ID[fa];
            for(int i = 0; i < K; i++) {
                all[as][i] = all[fid][i] + in[u][i];
//                all[as][i] %= 3;
                if(all[as][i] >= 3) all[as][i] -= 3;
            }
        } else {
            for(int i = 0; i < K; i++) {
                all[as][i] = in[u][i] ;
            }
        }
        ID[u] = as;
        as++;
        for(int i = head[u]; i != -1; i = nxt[i]) {
            int v = pnt[i];
            if(!Del[v] && v != fa) {
                Get_Dis(v,u);
            }
        }
    }
    void Solve(int u) { 
        //printf("u=%d\n",u);
        u = Get_Root(u);
      //  printf("u=%d\n",u);
        Ans += Calc(u,u,false);
     //  printf("Ans=%d\n",Ans);
     //   puts("ddd");
        Del[u] = true;
        for(int i = head[u]; i != -1; i = nxt[i]) {
            int v = pnt[i];
            if(!Del[v]) {
                int tmp = Ans;
             //   printf("v=%d\n",v);
                Ans -= Calc(v,u,true);
             //   printf("tmp=%d Ans=%d\n",tmp,Ans);
            }
        }
      //  printf("u=%d aaaa Ans=%d\n",u,Ans);
        for(int i = head[u]; i != -1; i = nxt[i]) {
            int v = pnt[i];
            if(!Del[v]) {
                Solve(v);
            }
        }

    }
    lld Calc(int u,int root,bool yes){
        as = 0;
        Get_Dis(u,-1);
      /*  for(int i = 0; i < as;i++) {
            for(int j = 0; j < K; j++) {
             //   printf("all[%d][%d]=%d\n",i,j,all[i][j]);
            }
        }*/
        if(yes) {
           // printf("u=%d root=%d\n",u,root);
            for(int i = 0; i < as; i++) {
                for(int j = 0; j < K; j++) {
                    all[i][j] += in[root][j];
                    if(all[i][j] >= 3) all[i][j] -= 3;
                }
            }
           /* for(int i = 0; i < as; i++) {
                for(int j = 0; j < K; j++) {

                    printf("all[%d][%d]=%d\n",i,j,all[i][j]);
                }
            }*/
        }
      //  printf("as=%d\n",as);
        lld ans = 0;
      //  ta.init();
       map<lld,int> tt;
        int start = (u == root) ? 1 : 0;
        for(int i = start; i < as; i++) {
            int x[33];
            lld sum = 0 , g = 0;
            bool f = true;
            
            for(int j = 0; j < K; j++) {
                if(all[i][j] == 0) x[j] = 0;
                if(all[i][j] == 1) x[j] = 2;
                if(all[i][j] == 2) x[j] = 1;
                g<<=2;
                g |= x[j];
                int tmp = all[i][j] - in[root][j];
                if(tmp < 0) tmp += 3 ;
                sum<<=2;
                sum |= tmp;
//                sum = sum * 10 + tmp;

                if(all[i][j] != 0) f = false;
            }
          // puts("x:::");
         //   for(int j = 0; j < K; j++) printf("%d ",x[j]);puts("");
         //   puts("y:::");
       //     for(int j = 0; j < K; j++) printf("%d ",y[j]);puts("");
            if(f && !yes) {
                ans++;
           //      puts("fffff");
            //    puts("ddd");
            }//printf("g=%d sum=%d\n",g,sum);
            ans += tt[g];
         //   printf("ans=%d\n",ans);
            tt[sum]++;
        }
      return ans;
  }
    lld gao() {
        Ans = 0;
        fill(Del,Del+n+1,false);
        Solve(1);
        return Ans;
    }
    lld Ans;
}nice;
int extr ;
void split(int node,lld num) {
    if(num == 0) return ;
    bool  f = true;
    for(int i = 0; i < K; i++) {
        in[node][i] = 0;
        if(num % pri[i] == 0) {
            while(num % pri[i] ==0) {
                num /= pri[i];
                in[node][i]++;
            }
        }
        in[node][i] %= 3;
        if(in[node][i] != 0) f =false; 
    }
    if(f) extr ++;
   // for(int i = 0; i < K; i++) printf("in[%d][%d]=%d\n",node,i,in[node][i]);
}
int get_val()
{     
    int ret(0);     
    char c;     
    while((c=getchar())==' '||c=='\n'||c=='\r');     
        ret=c-'0';     
    while((c=getchar())!=' '&&c!='\n'&&c!='\r')                 
            ret=ret*10+c-'0';     
        return ret;
}

int main() {
    while(scanf("%d",&n)!=EOF) {
        E = 0; extr = 0;
        fill(head,head+n+1,-1);
        scanf("%d",&K);
        for(int i = 0; i < K; i++) {
//            scanf("%d",&pri[i]);
              pri[i] = get_val();
        }
        lld num;
        for(int i = 1; i <= n; i++) {
            scanf("%I64d",&num);
            split(i,num);
        }
        E = 0;
        for(int i = 1,a,b; i < n; i++){
            a = get_val();
            b = get_val();
  //          scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }

        printf("%I64d\n",nice.gao()+extr);
    }
    return 0;
}
/*
4
2 2 5
100 10 100 10
1 2
2 3
3 4

7
1 2 
2 2 2 2  2 2 2
1 2
1 3
2 4
2 5
3 6
3 7

5
3 2 3 5
2500 200 9 270000 27
4 2
3 5
2 5
4 1

4
7
1

6
3 2 3 5
6 1 30 150 150 12
1 2
2 4
1 3
3 5
3 6

 */ 


你可能感兴趣的:(hdu 4670 点分治 + 哈希)