三元環&哈希表

標題這倆東西看起來似乎八杆子打不着,不過只是我在學三元環的時候纔剛學到哈希表是個什麼東西。。。
關於三元環的解法感覺Claris寫的就很不錯→%%Claris
我在這裏再簡單的說一下複雜度的相關;
首先可以改成單向邊,全都改成由大的點指向小的點(我自己寫的是相反的。。。)然後枚舉每一個點i,再枚舉這個點的出邊,如果連出的這個點(設爲k)出度小於sqrt(m)的話,再暴力枚舉一下另一個點,只看這一部分複雜度是n根號m的;
如果連出的點k的出度大於sqrt(m),那麼就暴力找所有i的其他出點,看是否能組成三元環,由於出度大於sqrt(m)的最多隻有sqrt(m)個點,所以這一部分是m根號m的;
至於第二種情況找第三個點的時候爲什麼要從一開始的i開始找,如果i出度大於根m,那i和k可能的組合是很少的,而如果i出度小於根號m,那i向外找的點是小於根號m的,總體平均下來還是m根號m
不得不說一下Claris神奇的寫法,他給每條邊先排了個序,再按順序插入鄰接表中,這樣保證每個點向外依次遍歷到的點是單調的,可以省掉一部分常數;
至於哈希表,之前一直以爲哈希表只是簡單的哈希,把值模一下放數組裏就完了,以至於我無數次臉黑撞哈希;
今天我纔剛發現,原來真正的哈希表是不會有哈希衝突的,其原理是將哈希值相同的數據存一個鄰接鏈表,每次都在這個鄰接鏈表裏遍歷一遍看是否有要查找的元素;
這樣一來正確性是可以保證的,而且由於撞哈希的概率不會太高,複雜度均攤下來也是O(1)的;

放一波代碼orz(感覺表達能力好弱。。。寫的這些個鬼東西將來自己都不一定能再看懂)

bzoj3498: PA2009 Cakes

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
const int maxn=100005;
using std::max;
const int maxm=250005;
int sq,v[maxn],du[maxn],n,m;
struct asd{
    int next,x,y;
}edge[maxm*4];
const int mod=(1<<23)-1;
int hnode[mod+1],node[maxn];
int etot=0;
void add(int x,int y){
    edge[++etot].next=node[x];
    edge[etot].y=y;
    node[x]=etot;
}
int hash(int x,int y){
    return (x<<8|y)&mod;
}
void insert(int x,int y){
    int val=hash(x,y);
    edge[++etot].next=hnode[val];
    edge[etot].x=x,edge[etot].y=y;
    hnode[val]=etot;
}
bool vis(int x,int y){
    int val=hash(x,y);
    for(int i=hnode[val];i;i=edge[i].next)if(edge[i].x==x&&edge[i].y==y)return true;
    return false;
}
void read(int &x){
    x=0;
    char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
}
int main()
{
//  freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    sq=sqrt((double)m)+0.5;
    for(int i=1;i<=n;i++)read(v[i]);
    while(m--){
        int tp1,tp2;
        read(tp1),read(tp2);
        if(tp1>tp2)std::swap(tp1,tp2);
        add(tp1,tp2);
        du[tp1]++;
        insert(tp1,tp2);
    }   
    LL ans=0;
    for(int i=1;i<=n;i++){
        for(int j=node[i];j;j=edge[j].next){
            int vi=v[edge[j].y]> v[i] ? v[edge[j].y] : v[i];
            if(du[edge[j].y]<sq){
                for(int k=node[edge[j].y];k;k=edge[k].next)
                    if(vis(i,edge[k].y))ans+=(LL)v[edge[k].y]>vi ? v[edge[k].y] : vi;
            }
            else {
                for(int k=node[i];k;k=edge[k].next){
                    if(edge[k].y>edge[j].y&&vis(edge[j].y,edge[k].y))ans+=(LL)v[edge[k].y]>vi ? v[edge[k].y] : vi;
                }
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

bzoj5206: [Jsoi2017]原力

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
const int maxn=100005;
using std::max;
const int maxm=250005;
int sq,du[maxn],n,m;
struct asd{
    int next,x,y,c;LL vi;
}edge[maxm*4];
const int mod=999983;
const int p=1000000007;
int hnode[mod],node[maxn];
int etot=0;
int add(int x,int y,LL v,int zt){
    edge[++etot].next=node[x];
    edge[etot].y=y;
    edge[etot].c=zt;
    edge[etot].vi=v;
    node[x]=etot;
    return etot;
}
int hash(int x,int y,int z){
    return(int)(((LL)x*(LL)n*8ll+(LL)y*8ll+z)%(LL)mod);
}
void insert(int x,int y,LL v,int zt){
    int val=hash(x,y,zt);
    edge[++etot].next=hnode[val];
    edge[etot].x=x,edge[etot].y=y;
    edge[etot].c=zt;
    edge[etot].vi=v;
    hnode[val]=etot;
}
int tot3=0;
int vis(int x,int y,int zt){
    int val=hash(x,y,zt);
    for(int i=hnode[val];i;i=edge[i].next){
        tot3++;
        if(edge[i].x==x&&edge[i].y==y&&edge[i].c==zt)return i;
    }
    return 0;
}
void read(int &x){
    x=0;
    char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
}
int main()
{
//  freopen("force.in","r",stdin);
//  freopen("force.out","w",stdout); 
//  freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    sq=sqrt((double)m)+0.5;
    while(m--){
        int tp1,tp2,tp3;
        read(tp1),read(tp2),read(tp3);
        char c[3];
        scanf("%s",c);
        int zt=0;
        if(c[0]=='R')zt=1;
        else if(c[0]=='G')zt=1<<1;
        else zt=1<<2;
        if(tp1>tp2)std::swap(tp1,tp2);
        int tv=vis(tp1,tp2,zt);
        if(!tv){
            add(tp1,tp2,(LL)tp3,zt);
            insert(tp1,tp2,(LL)tp3,zt);
            du[tp1]++;

        }
        else {
            (edge[tv].vi+=(LL)tp3)%=p,(edge[tv-1].vi+=(LL)tp3)%=p;

        }
    }   
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=node[i];j;j=edge[j].next){
            int zt=edge[j].c;
            if(du[edge[j].y]<=sq){
                for(int k=node[edge[j].y];k;k=edge[k].next)
                if(zt^edge[k].c)
                {
                    int nzt=7^zt^edge[k].c;
                    int tv=vis(i,edge[k].y,nzt);
                    if(tv)(ans+=(LL)(edge[tv].vi*edge[k].vi%p)*edge[j].vi%p)%=p;
                }
            }
            else {
                for(int k=node[i];k;k=edge[k].next)
                if(zt^edge[k].c)
                {
                    int nzt=7^zt^edge[k].c;
                    int tv=vis(edge[j].y,edge[k].y,nzt);
                    if(edge[k].y>edge[j].y&&tv)(ans+=(LL)(edge[tv].vi*edge[k].vi%p)*edge[j].vi%p)%=p;
                }
            }
        }
    }
    printf("%d\n",ans);
    return 0;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章