zoukankan      html  css  js  c++  java
  • [ural 2126]. Partition into Teams

    题意

    (n)个人,每个人可以站红队,可以站蓝队,也可以当观察者。
    红队获胜当且仅当站红队的人数大于站蓝队的人数。
    问红队获胜的方案数,对小质数(p)取模。
    (n leq {10} ^ {18}, p leq {10} ^ {6})

    题解

    列出式子:

    [sum_{i = 0} ^ n inom{n}{i} sum_{j = 0} ^ {lfloor frac{n - i - 1}{2} floor} inom{n - i}{j} ]

    发现后面这个东西相当于

    [sum_{i = 0} ^ n inom{n}{i} 2 ^ {n - i - 1} - sum_{i = 0} ^ n inom{n}{i} inom{n - i}{i} ]

    即将红队非输的方案数减去红队平的方案数得到的结果。
    发现上面的东西等于

    [frac{1}{2} left(3 ^ n - sum_{i = 0} ^ n inom{n}{i} inom{n - i}{i} ight) ]

    右边这东西怎么算?
    由于(p)比较小,而(n)比较大,不太方便处理阶乘,所以考虑用lucas定理。
    考虑在(p)进制下,(n = {(n_1, n_2, ldots, n_k)}_p)
    我们要枚举一个(i = {(i_1, i_2, ldots, i_k)}_p),将(inom{n}{i} inom{n - i}{i})计入答案。
    也即

    [inom{n_1}{i_1} inom{n_2}{i_2} ldots inom{n_k}{i_k} inom{{(n - i)}_1}{i_1} inom{{(n - i)}_2}{i_2} ldots inom{{(n - i)}_k}{i_k} ]

    考虑到上面的式子当且仅当(forall_w, n_w = i_w + {(n - i)_w})时不为0。否则(n_w + p = i_w + {(n - i)_w}),则有(n_w < i_w),那么(inom{n_w}{i_w})就为0了。
    那么我们可以对于总共(k)位,计算(prod_{w = 1} ^ {k} sum_{i = 0} ^ {p - 1} inom{n_w}{i} inom{n_w - i}{i} [i leq n_w][i leq n_w - i])即可。
    复杂度(mathcal O(p log_p n))

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e6 + 6, M = 64;
    ll n, mod, ans, tmp;
    ll fac[N], inv[N], a[M];
    ll power (ll x, ll y) {
    	ll ret = 1;
    	for ( ; y; y >>= 1, x = x * x % mod) {
    		if (y & 1) {
    			ret = ret * x % mod;
    		}
    	}
    	return ret;
    }
    void precalc () {
    	fac[0] = 1;
    	for (int i = 1; i < mod; ++i) {
    		fac[i] = fac[i - 1] * i % mod;
    	}
    	inv[mod - 1] = power(fac[mod - 1], mod - 2);
    	for (int i = mod - 2; ~i; --i) {
    		inv[i] = inv[i + 1] * (i + 1) % mod;
    	}
    }
    ll C (int n, int m) {
    	return n < m || m < 0 ? 0 : fac[n] * inv[m] % mod * inv[n - m] % mod;
    }
    ll calc () {
    	for ( ; n; n /= mod) {
    		a[++a[0]] = n % mod;
    	}
    	ll ret = 1, tmp;
    	for (int i = 1; i <= a[0]; ++i) {
    		tmp = 0;
    		for (int j = 0; j <= a[i] - j; ++j) {
    			tmp = (tmp + C(a[i], j) * C(a[i] - j, j)) % mod;
    		}
    		ret = ret * tmp % mod;
    	}
    	return ret;
    }
    int main () {
    	cin >> n >> mod, precalc();
    	ans = (power(3, n) - calc() + mod) % mod;
    	ans = ans * power(2, mod - 2) % mod;
    	cout << ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    Python基础—字符串
    Python基础—函数
    2019918练手爬虫日记
    python基础—列表
    Python urllib详解
    安装TesseractOCR显示无效的路径
    Sql server 关于ID突然自增问题解决方案
    Sql server 登陆后无法找不到数据库怎么解决
    Python常用语句及流程控制
    jquery cookie操作
  • 原文地址:https://www.cnblogs.com/psimonw/p/11795117.html
Copyright © 2011-2022 走看看