zoukankan      html  css  js  c++  java
  • 【模板】Polya 定理

    给定一个(n)个点,(n)条边的环,有(n)种颜色,给每个顶点染色,问有多少种本质不同的染色方案,答案对(10^9+7)取模

    注意本题的本质不同,定义为:只需要不能通过旋转与别的染色方案相同

    一种染色方案可以看做先染了前(d)个位置,然后将这一段复制(frac{n}{d})次拼接而成,其中(d|n)。我们称这个(d)为一种染色方案的周期(这里默认是最小正周期)。

    对于一个周期(循环个数)为(d)的染色方案,将它旋转(d)次会得到(d)个看起来不同但本质相同的染色方案。

    (f(x))表示周期为(x)的看上去不同的方案数。枚举周期(d),那么每一种周期的方案就多算(d)次,因此(ans=sumlimits_{d|n}dfrac{f(d)}{d})

    (f(x))不容易计算,但是我们知道:对于(n)的所有约数(d),将(f(d))求和就会得到总方案数(m^n),即

    [m^n=sumlimits_{d|n}f(d) ]

    莫比乌斯反演得

    [f(x)=sumlimits_{d|x}mu(frac{n}{d})m^d ]

    代入第一个式子得到

    [ans=sumlimits_{d|n}frac{1}{d}sumlimits_{k|d}mu(frac{d}{k})m^k ]

    [=sumlimits_{d|n}frac{d}{n}sumlimits_{k|frac{n}{d}}mu(frac{n}{dk})m^k ]

    [=frac{1}{n}sumlimits_{d|n}dsumlimits_{k|frac{n}{d}}mu(frac{n}{dk})m^k ]

    [=frac{1}{n}sumlimits_{k|n}m^ksumlimits_{d|frac{n}{k}}dmu(frac{n}{dk}) ]

    [=frac{1}{n}sumlimits_{k|n}m^kvarphi(n/k) ]

    上面设颜色的数量为(m)是为了避免混淆,本题中(m=n)

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int mod = 1e9 + 7;
    
    int t, n, m;
    
    unordered_map < int, int > fphi;
    
    int read()
    {
    	int x = 0, fl = 1; char ch = getchar();
    	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = x * 10ll + ch - '0'; ch = getchar();}
    	return x * fl;
    }
    
    int qpow(int base, int pw)
    {
    	int s = 1;
    	while (pw)
    	{
    		if (pw & 1) s = 1ll * s * base % mod;
    		base = 1ll * base * base % mod;
    		pw >>= 1;
    	}
    	return s;
    }
    
    int phi(int x)
    {
    	if (fphi[x]) return fphi[x];
    	int t = x, y = x;
    	for (int i = 2; i <= m; i ++ )
    	{
    		if ((x % i) == 0)
    		{
    			t = t / i * (i - 1);
    			while ((x % i) == 0) x /= i;
    		}
    	}
    	if (x > 1) t = t / x * (x - 1);
    	return fphi[y] = t;
    }
    
    int main()
    {
    	t = read();
    	while (t -- )
    	{
    		n = read(), m = (int)(sqrt(n));
    		int res = 0;
    		for (int k = 1; k <= m; k ++ )
    		{
    			if (n % k) continue;
    			res = (res + 1ll * qpow(n, k) * phi(n / k) % mod) % mod;
    			if (k * k != n) res = (res + 1ll * qpow(n, n / k) * phi(k) % mod) % mod;
    		}
    		res = 1ll * res * qpow(n, mod - 2) % mod;
    		printf("%d
    ", res);
    	}
    	return 0;
    }
    
  • 相关阅读:
    《STL源码剖析》 stl_multimap.h [转]
    2007元旦粤北山区:英西峰林走廊,小赵州桥
    东师回忆录 之 二舍被拆记
    学生二三事
    2007元旦粤北山区:乳源大峡谷
    元旦粤北骑游计划
    通过配置php来屏蔽PHP错误
    什么是负载平衡
    ORACLE 日期函数大全
    linux 如何运行sh文件
  • 原文地址:https://www.cnblogs.com/andysj/p/14582189.html
Copyright © 2011-2022 走看看