zoukankan      html  css  js  c++  java
  • 「6月雅礼集训 2017 Day5」学外语

    【题目大意】

    给出${P_i}$,求经过以下操作后能够得到的不同序列个数:

    第一步,选择$i, j$,交换$P_i,P_j$;第二步,把所有$P_x=i$的$P_x$变为$j$,把所有$P_x=j$的$P_x$变为$i$。

    $n leq 10^5$

    【题解】

    显然就是求

    给出一个基环内向森林,求交换编号后,不同构的个数。

    考虑什么时候会发生同构的情况。

    容易发现,每当出现k个子树相同,或k个环套树相同,就有 k! 种同构方案。

    那么我们只需要做一遍树哈希、环套树哈希(可以用最小表示法,或者按照哈希值最小作为起点)来处理。

    代码好难写。。。

    还被卡哈希了。。还没调处来qwq

    upd: 是我找循环节错了

    最小表示法:

    # include <map>
    # include <math.h>
    # include <vector>
    # include <stdio.h>
    # include <assert.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10, N = 2e5 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    inline int getint() {
        int x = 0; char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
        return x;
    }
    
    int n, p[M], ans, fuckyou = 1;
    struct Graph {
        int n, head[N], nxt[M], to[M], tot;
        inline void set(int _n) {
            n = _n; tot = 0;
            for (int i=1; i<=n; ++i) head[i] = 0;
        }
        inline void add(int u, int v) {
            ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
        }
        inline void adde(int u, int v) {
            add(u, v), add(v, u);
        }
    }G;
    
    struct us {
        int fa[N], n;
        inline void set(int _n) {
            n = _n; for (int i=1; i<=n; ++i) fa[i] = i;
        }
        inline int getf(int x) {
            return fa[x] == x ? x : fa[x] = getf(fa[x]);
        }
        inline void un(int fu, int fv) {
            fa[fu] = fv;
        }
    }U;
    
    vector<int> ring[N]; int rn = 0; 
    
    namespace FACINV {
        int fac[N], inv[N], Inv[N];
        
        inline int pwr(int a, int b, int P = mod) {
            int ret = 1;
            while(b) {
                if(b&1) ret = 1ll * ret * a % P;
                a = 1ll * a * a % P;
                b >>= 1;
            }
            return ret;
        }
        
        inline void prepare() {
            fac[0] = 1; inv[0] = 1;
            for (int i=1; i<=100000; ++i) fac[i] = 1ll * fac[i-1] * i % mod;
            inv[100000] = pwr(fac[100000], mod-2);
            for (int i=99999; i; --i) inv[i] = 1ll * inv[i+1] * (i+1) % mod;
            for (int i=99999; i; --i) Inv[i+1] = 1ll * inv[i+1] * fac[i] % mod;
            Inv[1] = 1;
        }
        
        inline int gP(int x, int y) {
            assert(x >= y);
            return 1ll * fac[x] * inv[x-y] % mod;
        }
        
        inline int gC(int x, int y) {
            assert(x >= y);
            return 1ll * fac[x] * inv[x-y] % mod * inv[y] % mod;
        }
    }
    
    using namespace FACINV;
    
    namespace SOLVE_RINGS {
        bool inrings[N];
        int c[N], cn = 0, deg[N]; 
        bool vis[N]; 
        inline void dfs_rings(int x) {
            if(vis[x]) {
                ++rn; for (int i=cn; i; --i) ring[rn].push_back(c[i]);
                return ;
            }
            c[++cn] = x; vis[x] = 1; 
            for (int i=G.head[x]; i; i=G.nxt[i]) ++deg[x], dfs_rings(G.to[i]);
            --cn;
        }
        
        inline void find_rings() {
             U.set(n);
            for (int i=1; i<=n; ++i) {
                RG int fu = U.getf(p[i]), fv = U.getf(i);            
                if(fu == fv) inrings[i] = 1;
                else U.un(fu, fv);
            }
            for (int i=1; i<=n; ++i) {
                if(!inrings[i]) continue;
                cn = 0;
                dfs_rings(i);
            }
        }             
        
        inline void debug_rings() {
            for (int i=1; i<=rn; ++i) {
                printf("num = %d
      ", i);
                 for (int j=0; j<ring[i].size(); ++j)
                     cout << ring[i][j] << ' ';
                cout << endl;
            }
        }
        
        inline void clear_rings() {
            for (int i=1; i<=rn; ++i) ring[i].clear(); 
            for (int i=1; i<=n; ++i) inrings[i] = vis[i] = deg[i] = 0;
            rn = 0;
        }
    }
    
    using namespace SOLVE_RINGS;
    
    struct pa {
        ull hash; int sz;
        pa() {}
        pa(ull hash, int sz) : hash(hash), sz(sz) {}
    };
    ull HA[M], HB[M];
    
    vector<pa> tem;
    inline void debug_tem() {
        for (int i=0; i<tem.size(); ++i)
            printf("hash = %lld,  size = %d
    ", tem[i].hash, tem[i].sz);
    }
    
    inline bool cmp_hash(pa a, pa b) {
        return a.hash < b.hash;
    } 
    
    inline void gs(bool flag) {
        if(flag) sort(tem.begin(), tem.end(), cmp_hash);
        for (int i=0, j, t; i<tem.size(); i=j) {
            j = i; while(j<tem.size() && tem[j].hash == tem[i].hash) ++j;
            fuckyou = 1ll * fuckyou * fac[j-i] % mod;
        }
    }
    
    inline void gs2() {
        int sz = tem.size();
        for (int i=1; i*i<=sz; ++i) {
            if(sz % i == 0) {
                bool gg = 0;
                int d = sz/i;
                for (int j=0; j<sz; ++j) {
                    if(tem[j].hash != tem[(j-i+sz) % sz].hash) {
                        gg = 1;
                        break;
                    }
                }
                if(!gg) {
                    fuckyou = 1ll * fuckyou * d % mod;
                    return ;
                }
            }
        }
        for (int i=sqrt(sz); i; --i) {
            if(sz % i == 0) {
                bool gg = 0;
                int d = i;
                for (int j=0; j<sz; ++j) {
                    if(tem[j].hash != tem[(j-sz/i+sz) % sz].hash) {
                        gg = 1;
                        break;
                    }
                }
                if(!gg) {
                    fuckyou = 1ll * fuckyou * d % mod;
                    return ;
                }
            }
        }
        return ;
    }
    
    inline int mininum() {
        int i=0, j=1, len = tem.size(), l;
        while(i<len && j<len) {
            for (l=0; l<len; ++l) if(tem[(i+l)%len].hash != tem[(j+l)%len].hash) break;
            if(l>len) break;
            if(tem[(i+l)%len].hash > tem[(j+l)%len].hash) i = i+l+1;
            else j = j+l+1;
            if(i == j) j = i+1;
        }
        if(i<j) return i;
        else return j;
    }
    
    pa f[N], g[N];
    int sze[N];
    inline void dfs_tree(int x, int fa = 0, int d = 0) {
        sze[x] = 1;
        for (int i=G.head[x]; i; i=G.nxt[i]) {
            if(G.to[i] == fa) continue;
            dfs_tree(G.to[i], x, d+1);
            sze[x] += sze[G.to[i]];
        }
        tem.clear();
        int sons = 0;
        for (int i=G.head[x]; i; i=G.nxt[i]) {
            if(G.to[i] == fa) continue;
            tem.push_back(f[G.to[i]]); ++ sons;
        }
        sort(tem.begin(), tem.end(), cmp_hash);
        ull hsh = 666623333ull;
        for (int i=0; i<tem.size(); ++i) hsh = (hsh << 13) ^ ((hsh & tem[i].hash) << 7) + ((67 * hsh ^ tem[i].hash) >> 13) ^ (tem[i].hash << 5);
        gs(0); hsh = hsh ^ HA[sze[x]] + HB[sons];
        f[x] = pa(hsh, sze[x]);
    }
    
    inline pa deal(vector<int> r) {
        int SZ = 0;
        for (int i=0; i<r.size(); ++i) {
            int nx = r[(i-1 + r.size()) % r.size()];
            dfs_tree(r[i], nx);    
            SZ += sze[r[i]];
        }
        tem.clear();
        for (int i=0; i<r.size(); ++i) tem.push_back(f[r[i]]);
    //    debug_tem();
        int fro = mininum();
        ull hsh = 19260817ull;
        for (int i=0; i<tem.size(); ++i) {
            int j = (i + fro) % tem.size();
            hsh = (hsh << 7) ^ ((hsh & tem[j].hash) >> 2) + (103 * hsh & tem[j].hash) ^ ((233 * tem[j].hash ^ hsh) << 19) ^ (tem[j].hash + 233);
        }
        hsh = hsh ^ HA[SZ]; 
        gs2();
        pa ret = pa(hsh, SZ);
        return ret;
    }
    
    
    inline void sol() {
        n = getint(); G.set(n); ans = fac[n]; fuckyou = 1;
        for (int i=1; i<=n; ++i) {
            p[i] = getint();
            G.add(p[i], i);
        }
        
        find_rings(); 
    //    debug_rings(); 
        
        for (int i=1; i<=rn; ++i) g[i] = deal(ring[i]);
        
        tem.clear();
        for (int i=1; i<=rn; ++i) tem.push_back(g[i]);
        gs(1);
        ans = 1ll * ans * pwr(fuckyou, mod-2) % mod;
        --ans; if(ans < 0) ans += mod;
        cout << ans << endl;
        clear_rings(); 
    }
    
    inline ull irand() {
        ull t = 0;
        for (int i=0; i<=6; ++i) t = (t<<15) + rand();
        return t;
    }
    
    int main() {
        freopen("langue.in", "r", stdin);
        freopen("langue.out", "w", stdout);
        prepare();
        for (int i=1; i<=n+n; ++i) HA[i] = irand(), HB[i] = irand();
        int T; T = getint();
        while(T--) sol();
        return 0;
    }
    View Code

    我们直接找哈希最大值作为起点也行(可能出题人卡了最小值23333)

    # include <map>
    # include <math.h>
    # include <vector>
    # include <stdio.h>
    # include <assert.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10, N = 2e5 + 10;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    inline int getint() {
        int x = 0; char ch = getchar();
        while(!isdigit(ch)) ch = getchar();
        while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
        return x;
    }
    
    int n, p[M], ans, fuckyou = 1;
    struct Graph {
        int n, head[N], nxt[M], to[M], tot;
        inline void set(int _n) {
            n = _n; tot = 0;
            for (int i=1; i<=n; ++i) head[i] = 0;
        }
        inline void add(int u, int v) {
            ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
        }
        inline void adde(int u, int v) {
            add(u, v), add(v, u);
        }
    }G;
    
    struct us {
        int fa[N], n;
        inline void set(int _n) {
            n = _n; for (int i=1; i<=n; ++i) fa[i] = i;
        }
        inline int getf(int x) {
            return fa[x] == x ? x : fa[x] = getf(fa[x]);
        }
        inline void un(int fu, int fv) {
            fa[fu] = fv;
        }
    }U;
    
    vector<int> ring[N]; int rn = 0; 
    
    namespace FACINV {
        int fac[N], inv[N], Inv[N];
        
        inline int pwr(int a, int b, int P = mod) {
            int ret = 1;
            while(b) {
                if(b&1) ret = 1ll * ret * a % P;
                a = 1ll * a * a % P;
                b >>= 1;
            }
            return ret;
        }
        
        inline void prepare() {
            fac[0] = 1; inv[0] = 1;
            for (int i=1; i<=100000; ++i) fac[i] = 1ll * fac[i-1] * i % mod;
            inv[100000] = pwr(fac[100000], mod-2);
            for (int i=99999; i; --i) inv[i] = 1ll * inv[i+1] * (i+1) % mod;
            for (int i=99999; i; --i) Inv[i+1] = 1ll * inv[i+1] * fac[i] % mod;
            Inv[1] = 1;
        }
        
        inline int gP(int x, int y) {
            assert(x >= y);
            return 1ll * fac[x] * inv[x-y] % mod;
        }
        
        inline int gC(int x, int y) {
            assert(x >= y);
            return 1ll * fac[x] * inv[x-y] % mod * inv[y] % mod;
        }
    }
    
    using namespace FACINV;
    
    namespace SOLVE_RINGS {
        bool inrings[N];
        int c[N], cn = 0, deg[N]; 
        bool vis[N]; 
        inline void dfs_rings(int x) {
            if(vis[x]) {
                ++rn; for (int i=cn; i; --i) ring[rn].push_back(c[i]);
                return ;
            }
            c[++cn] = x; vis[x] = 1; 
            for (int i=G.head[x]; i; i=G.nxt[i]) ++deg[x], dfs_rings(G.to[i]);
            --cn;
        }
        
        inline void find_rings() {
             U.set(n);
            for (int i=1; i<=n; ++i) {
                RG int fu = U.getf(p[i]), fv = U.getf(i);            
                if(fu == fv) inrings[i] = 1;
                else U.un(fu, fv);
            }
            for (int i=1; i<=n; ++i) {
                if(!inrings[i]) continue;
                cn = 0;
                dfs_rings(i);
            }
        }             
        
        inline void debug_rings() {
            for (int i=1; i<=rn; ++i) {
                printf("num = %d
      ", i);
                 for (int j=0; j<ring[i].size(); ++j)
                     cout << ring[i][j] << ' ';
                cout << endl;
            }
        }
        
        inline void clear_rings() {
            for (int i=1; i<=rn; ++i) ring[i].clear(); 
            for (int i=1; i<=n; ++i) inrings[i] = vis[i] = deg[i] = 0;
            rn = 0;
        }
    }
    
    using namespace SOLVE_RINGS;
    
    struct pa {
        ull hash; int sz;
        pa() {}
        pa(ull hash, int sz) : hash(hash), sz(sz) {}
    };
    ull HA[M], HB[M];
    
    vector<pa> tem;
    inline void debug_tem() {
        for (int i=0; i<tem.size(); ++i)
            printf("hash = %lld,  size = %d
    ", tem[i].hash, tem[i].sz);
    }
    
    inline bool cmp_hash(pa a, pa b) {
        return a.hash < b.hash;
    } 
    
    inline void gs(bool flag) {
        if(flag) sort(tem.begin(), tem.end(), cmp_hash);
        for (int i=0, j, t; i<tem.size(); i=j) {
            j = i; while(j<tem.size() && tem[j].hash == tem[i].hash) ++j;
            fuckyou = 1ll * fuckyou * fac[j-i] % mod;
        }
    }
    
    inline void gs2() {
        int sz = tem.size();
        for (int i=1; i*i<=sz; ++i) {
            if(sz % i == 0) {
                bool gg = 0;
                int d = sz/i;
                for (int j=0; j<sz; ++j) {
                    if(tem[j].hash != tem[(j-i+sz) % sz].hash) {
                        gg = 1;
                        break;
                    }
                }
                if(!gg) {
                    fuckyou = 1ll * fuckyou * d % mod;
                    return ;
                }
            }
        }
        for (int i=sqrt(sz); i; --i) {
            if(sz % i == 0) {
                bool gg = 0;
                int d = i;
                for (int j=0; j<sz; ++j) {
                    if(tem[j].hash != tem[(j-sz/i+sz) % sz].hash) {
                        gg = 1;
                        break;
                    }
                }
                if(!gg) {
                    fuckyou = 1ll * fuckyou * d % mod;
                    return ;
                }
            }
        }
        return ;
    }
    
    inline int mininum() {
        ull mi = tem[0].hash; int id = 0;
        for (int i=1; i<tem.size(); ++i) 
            if(tem[i].hash > mi) mi = tem[i].hash, id = i;
        return id;
    }
    
    pa f[N], g[N];
    int sze[N];
    inline void dfs_tree(int x, int fa = 0, int d = 0) {
        sze[x] = 1;
        for (int i=G.head[x]; i; i=G.nxt[i]) {
            if(G.to[i] == fa) continue;
            dfs_tree(G.to[i], x, d+1);
            sze[x] += sze[G.to[i]];
        }
        tem.clear();
        int sons = 0;
        for (int i=G.head[x]; i; i=G.nxt[i]) {
            if(G.to[i] == fa) continue;
            tem.push_back(f[G.to[i]]); ++ sons;
        }
        sort(tem.begin(), tem.end(), cmp_hash);
        ull hsh = 666623333ull;
        for (int i=0; i<tem.size(); ++i) hsh = (hsh << 13) ^ ((hsh & tem[i].hash) << 7) + ((67 * hsh ^ tem[i].hash) >> 13) ^ (tem[i].hash << 5);
        gs(0); hsh = hsh ^ HA[sze[x]] + HB[sons];
        f[x] = pa(hsh, sze[x]);
    }
    
    inline pa deal(vector<int> r) {
        int SZ = 0;
        for (int i=0; i<r.size(); ++i) {
            int nx = r[(i-1 + r.size()) % r.size()];
            dfs_tree(r[i], nx);    
            SZ += sze[r[i]];
        }
        tem.clear();
        for (int i=0; i<r.size(); ++i) tem.push_back(f[r[i]]);
    //    debug_tem();
        int fro = mininum();
        ull hsh = 19260817ull;
        for (int i=0; i<tem.size(); ++i) {
            int j = (i + fro) % tem.size();
            hsh = (hsh << 7) ^ ((hsh & tem[j].hash) >> 2) + (103 * hsh & tem[j].hash) ^ ((233 * tem[j].hash ^ hsh) << 19) ^ (tem[j].hash + 233);
        }
        hsh = hsh ^ HA[SZ]; 
        gs2();
        pa ret = pa(hsh, SZ);
        return ret;
    }
    
    
    inline void sol() {
        n = getint(); G.set(n); ans = fac[n]; fuckyou = 1;
        for (int i=1; i<=n; ++i) {
            p[i] = getint();
            G.add(p[i], i);
        }
        
        find_rings(); 
    //    debug_rings(); 
        
        for (int i=1; i<=rn; ++i) g[i] = deal(ring[i]);
        
        tem.clear();
        for (int i=1; i<=rn; ++i) tem.push_back(g[i]);
        gs(1);
        ans = 1ll * ans * pwr(fuckyou, mod-2) % mod;
        --ans; if(ans < 0) ans += mod;
        cout << ans << endl;
        clear_rings(); 
    }
    
    inline ull irand() {
        ull t = 0;
        for (int i=0; i<=6; ++i) t = (t<<15) + rand();
        return t;
    }
    
    int main() {
        freopen("langue.in", "r", stdin);
        freopen("langue.out", "w", stdout);
        prepare();
        for (int i=1; i<=n+n; ++i) HA[i] = irand(), HB[i] = irand();
        int T; T = getint();
        while(T--) sol();
        return 0;
    }
    View Code
  • 相关阅读:
    Android命名规范(重点讲解:包名)
    ADT中创建Android的Activity
    Android页面切换
    js技巧
    记一次查询超时的解决方案The timeout period elapsed......
    Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置
    SQL索引详解
    php 微信公众号接入支付宝支付
    【MVC】关于Action返回结果类型的事儿(上)
    H5网站接入支付宝的支付接口
  • 原文地址:https://www.cnblogs.com/galaxies/p/20170621_c.html
Copyright © 2011-2022 走看看