• 博士之时 [分类讨论, 计数]


    博士之时


    在这里插入图片描述


    color{red}{正解部分}

    由于

    • 0M1,M2N20 le M_1, M_2 le frac{N}{2}
    • 两个点之间至多有 11相同的边
    • 每个点至多链出 11同种边

    因此每个点最多向外链出 22不同的边, 进而得出 图中仅有 偶环, 且是 0,10,1 相间的 .

    接下来 分类讨论:

    • 偶环: 旋转同构 + 对称同构 = n2+n2=nfrac{n}{2} + frac{n}{2} = n .
    • 0,10,1 奇链: 仅正向编号 合法, 贡献为 11 .
    • 1,11,1 偶链: 以中间的边为对称轴翻转, 正向编号, 反向编号 合法, 贡献为 22 .
    • 0,00, 0 偶链: 同上 .

    又因为完全相同的 可以任意排列,

    于是答案为


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int mod = 1e9 + 7;
    const int maxn = 1e6 + 10;
    
    int N;
    int M1;
    int M2;
    int num0;
    int du[maxn];
    int fac[maxn];
    int head[maxn];
    int cnt_1[maxn];
    int cnt_3[maxn];
    int cnt_2[2][maxn];
    
    bool vis[maxn];
    
    struct Edge{ int nxt, to, w; } edge[maxn << 1];
    
    void Add(int from, int to, int w){ edge[++ num0] = (Edge){ head[from], to, w }; head[from] = num0; }
    
    int Ksm(int a, int b){
            int s = 1;
            while(b){
                    if(b & 1) s = 1ll*s*a % mod;
                    a = 1ll*a*a % mod; b >>= 1;
            }
            return s;
    }
    
    int main(){
            read();
            N = read(), M1 = read(), M2 = read();
            fac[0] = 1; for(reg int i = 1; i <= N; i ++) fac[i] = 1ll*fac[i-1]*i % mod;
            for(reg int i = 1; i <= M1; i ++){
                    int u = read(), v = read();
                    Add(u, v, 0), Add(v, u, 0);
                    du[u] ++, du[v] ++;
            }
            for(reg int i = 1; i <= M2; i ++){
                    int u = read(), v = read();
                    Add(u, v, 1), Add(v, u, 1);
                    du[v] ++, du[u] ++;
            }
            for(reg int i = 1; i <= N; i ++)
                    if(!vis[i] && du[i] == 1){
                            int x = i, s = 0;
                            while(!vis[x]){
                                    vis[x] = 1, s ++;
                                    for(reg int j = head[x]; j; j = edge[j].nxt)
                                            if(!vis[edge[j].to]) x = edge[j].to;
                            }
                            if(s & 1) cnt_1[s] ++;
                            else cnt_2[edge[head[i]].w][s] ++;
                    }
            for(reg int i = 1; i <= N; i ++)
                    if(!vis[i]){
                            int x = i, s = 0;
                            while(!vis[x]){
                                    vis[x] = 1, s ++;
                                    for(reg int j = head[x]; j; j = edge[j].nxt)
                                            if(!vis[edge[j].to]) x = edge[j].to;
                            }
                            cnt_3[s] ++;
                    }
            int Ans = 1;
            for(reg int i = 1; i <= N; i ++){
                    if(cnt_1[i]) Ans = 1ll*Ans*fac[cnt_1[i]] % mod;
                    if(cnt_3[i]) Ans = 1ll*Ans*Ksm(i, cnt_3[i])%mod*fac[cnt_3[i]]%mod;
                    if(cnt_2[0][i]) Ans = 1ll*Ans*Ksm(2, cnt_2[0][i])%mod*fac[cnt_2[0][i]]%mod;
                    if(cnt_2[1][i]) Ans = 1ll*Ans*Ksm(2, cnt_2[1][i])%mod*fac[cnt_2[1][i]]%mod;
            }
            Ans = (fac[N] - Ans + mod) % mod; printf("%d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    mysql5.5 uuid做主键与int做主键的性能实测
    dom4j解析xml字符串实例
    spring自动注入是单例还是多例?单例如何注入多例?
    Spring中Bean的五个作用域
    【总结】瞬时高并发(秒杀/活动)Redis方案
    浅谈分布式事务
    基于Redis实现分布式锁
    MySQL事务隔离级别详解
    Redis学习手册(Sorted-Sets数据类型)
    Redis的快照持久化-RDB与AOF
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822418.html
Copyright © 2020-2023  润新知