【Burnside引理】疫苗

来源:互联网 发布:河南的网络歌手 编辑:程序博客网 时间:2024/04/29 09:23

疫苗  by 胡泽聪

【题目大意】N个点的环,初始时每个点的颜色都是白色。要选出一些点(至少一个),把他们染成黑色,满足任意长度为k的区间中只能选最多一个点被染黑。求有多少钟染色方法。如果视循环同构的染色方法为本质相同的,求有多少种本质不同的染色方案。

【题解】这题题解不打好写,看看代码找找感觉,burnside引理。

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for (int i = a;i <= b;i ++)using namespace std;typedef long long LL;const int maxn = 100005;const int P = 1000000007;int N,K;int f[maxn],phi[maxn];void Task1(){fo(i,1,K) f[i] = 1;int ans = K;fo(i,K+1,N-K+1){f[i] = (f[i-1] + f[i-K]) % P;ans = (ans + f[i]) % P;}fo(i,N-K+2,N) ans = (ans + f[N-K+1]) % P;printf("%d\n",ans);}void Getphi(){static int prime[maxn];static bool notprime[maxn];int tot = 0;phi[1] = 1;fo(i,2,N){if (!notprime[i]) prime[++tot] = i, phi[i] = i-1;fo(j,1,tot){if (i * prime[j] > N) break;notprime[i*prime[j]] = 1;if (i % prime[j] == 0){phi[i*prime[j]] = phi[i] * prime[j];break;}phi[i*prime[j]] = phi[i] * phi[prime[j]];}}}inline int POW(int x,int y){if (!y) return 1;int ret = POW(x,y/2);ret = (LL)ret * ret % P;if (y & 1) ret = (LL)ret * x % P;return ret;}inline int F(int N){int ret = 0;if (K > N) return ret;fo(i,1,N-K+1) ret = (ret + f[i]) % P;fo(i,N-K+2,N) ret = (ret + f[N-K+1]) % P;return ret;}void Task2(){Getphi();LL ans = 0;fo(i,1,N){if (N % i != 0) continue;ans = (ans + (LL)F(N/i)*phi[i] % P) % P;}ans = (LL)ans * POW(N,P-2) % P;printf("%d\n",ans);}int main(){scanf("%d%d",&N,&K);Task1();Task2();return 0;}

再贴一个代码,两者后面的burnside引理的式子是等价的,上面的代码要快些。

#include<cstdio>#include<cstring>using namespace std;typedef long long LL;const int N = int(1e5);const int MOD = int(1e9 + 7);int dp[N], n, k;int gcd(int x, int y){return y ? gcd(y, x%y) : x;}int power(int x, int y){if(!y) return 1;int ret(power(x,y/2));ret = (LL(ret) * ret) % MOD;if(y&1) ret = (LL(ret) * x)%MOD;return ret;}int opt(int n){if(k > n) return 0;int cal = n - k - k + 1, ret(0);if(cal>0) ret = (LL(dp[cal]) * k) % MOD;for(int i=cal-1; i>0; i--) ret = (ret + dp[i]) % MOD;ret = (ret + n) % MOD;return ret;}int main(){scanf("%d%d", &n, &k);dp[1] = 1;for(int i=2; i<=n; i++){dp[i] = (i>k) ?  (dp[i-1] + dp[i-k] + 1) % MOD : (dp[i-1] + 1) % MOD;}int ans = opt(n), ret(0);for(int i=1; i<=n; i++) ret = (ret + opt(gcd(i,n))) % MOD;ret = (LL(ret) * power(n, MOD-2)) % MOD;printf("%d\n%d\n", ans, ret);return 0;}





0 0