zoukankan      html  css  js  c++  java
  • 2021杭电多校1 1011/HDU 6960 Necklace of Beads

    题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=6960

    题目大意:一串手链有n个珠子,有三种颜色红蓝绿,求相邻颜色不同且绿色染色数不超过k的本质不同的染色方案数,这里说的本质不同为两种染色方案不能通过旋转相同

    题目思路:根据Burnside原理

    [|X/G|=frac{1}{|G|}sum_{gin G} |X^g| ]

    (f_{n,m})为给n个珠子染色,绿色不超过m的不考虑本质不同的染色方案数,根据Pólya原理,旋转i个会将置换分为gcd(i,n)段,每段长(frac{n}{gcd(i,n)}),这种情况下的不动点可看做(f_{gcd(i,n),j})

    [ans =frac{1}{n}sum_{i=1}^{n}sum_{j=0}^{lfloor frac{kcdotmathrm{gcd}(i,n)}{n} floor} f_{gcd(i,n),j}\ =frac{1}{n}sum_{d|n}sum_{i=1}^{n}[mathrm{gcd}(i,n)=d]sum_{j=0}^{lfloor frac{kd}{n} floor} f_{d,j}\ =frac{1}{n}sum_{d|n}sum_{i=1}^{lfloorfrac{n}{d} floor}[mathrm{gcd}(i,n)=1]sum_{j=0}^{lfloor frac{kd}{n} floor}f_{d,j}\ =frac{1}{n}sum_{d|n}varphi(lfloorfrac{n}{d} floor)F(d,left lfloor frac{kd}{n} ight floor) ]

    现在问题转化成如何求(f_{n,m}),首先假设我们放好了m个绿色后会形成m个空,每个空都有2种情况:红蓝红蓝红……,蓝红蓝红蓝……,共(2^{m})种情况,然后我们考虑怎么放绿色的,放绿色点的方案数等于在长度为n的手链上选取m个不相邻的点的方案数,也分两种情况,假设现在放了0个绿色的点,即在剩下的n-m个空中放m个绿色,方案数为(Cinom{m}{n-m}),假设现在放了1个绿色的点,其左右都不能放绿色,即在剩下的n-m-1个空中放m-1个绿色,方案数为(Cinom{m-1}{n-m-1}),故(f_{n,m}=2^{m}left (Cinom{m}{n-m}+Cinom{m-1}{n-m-1} ight ))

    AC代码:
    话说C++超时了但G++AC了

    #include <unordered_map>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <string>
    #include <stack>
    #include <deque>
    #include <queue>
    #include <cmath>
    #include <map>
    #include <set>
    using namespace std;
    typedef pair<int, int> PII;
    typedef pair<double, int> PDI;
    typedef long long ll;
    typedef unsigned long long ull;
    const int INF = 0x3f3f3f3f;
    const int N = 1e6 + 10, M = 4e7 + 10;
    const int base = 1e9;
    const int P = 131;
    const int mod = 998244353;
    const double eps = 1e-8;
    const double PI = acos(-1.0);
    ll fac[N], inv[N], pow2[N];
    int phi[N], pri[N];
    bool st[N];
    int pos;
    ll ksm(ll a, ll b)
    {
    	ll res = 1 % mod;
    	while (b)
    	{
    		if (b & 1)
    			res = (res * a) % mod;
    		a = (a * a) % mod;
    		b >>= 1;
    	}
    	return res;
    }
    void inif(int n)
    {
    	phi[1] = 1;
    	for (int i = 2; i <= n; ++i)
    	{
    		if (!st[i])
    		{
    			phi[i] = i - 1;
    			pri[++pos] = i;
    		}
    		for (int j = 1; pri[j] <= n / i; ++j)
    		{
    			st[pri[j] * i] = true;
    			if (i % pri[j] == 0)
    			{
    				phi[pri[j] * i] = phi[i] * pri[j];
    				break;
    			}
    			phi[pri[j] * i] = phi[i] * (pri[j] - 1);
    		}
    	}
    	fac[0] = inv[0] = 1;
    	for (int i = 1; i < n; ++i)
    	{
    		fac[i] = (fac[i - 1] * i) % mod;
    		inv[i] = ksm(fac[i], mod - 2);
    	}
    	pow2[0] = 1;
    	for (int i = 1; i < n; ++i)
    		pow2[i] = pow2[i - 1] * 2 % mod;
    }
    ll C(ll n, ll m)
    {
    	return fac[n] * inv[m] % mod * inv[n - m] % mod;
    }
    ll F(ll n, ll k)
    {
    	ll res = n & 1 ? 0 : 2;
    	for (ll m = 1; m <= min(k, n / 2); ++m)
    		res = (res + pow2[m] * (C(n - m, m) + C(n - m - 1, m - 1)) % mod) % mod;
    	return res;
    }
    int main()
    {
    	inif(N - 1);
    	int T;
    	scanf("%d", &T);
    	while (T--)
    	{
    		ll n, k;
    		scanf("%lld%lld", &n, &k);
    		ll ans = 0;
    		for (ll i = 1; i * i <= n; ++i)
    		{
    			if (n % i == 0)
    			{
    				ll d = i;
    				ans = (ans + phi[n / d] * F(d, k * d / n) % mod) % mod;
    				if (i != n / i)
    				{
    					d = n / i;
    					ans = (ans + phi[n / d] * F(d, k * d / n) % mod) % mod;
    				}
    			}
    		}
    		ans = ans * ksm(n, mod - 2) % mod;
    		printf("%lld
    ", ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    如何获取显示器的EDID信息
    VGA
    RK3288 GMAC整理
    基于嵌入式Linux的千兆以太网卡驱动程序设计及测试
    module_param和module_param_array用法
    OSI七层协议模型、TCP/IP四层模型学习笔记
    999
    git
    最小生成树 (Minimum Spanning Tree,MST) --- Kruskal算法
    并查集 (Disjoint Set)
  • 原文地址:https://www.cnblogs.com/xiaopangpangdehome/p/15057084.html
Copyright © 2011-2022 走看看