• 【BZOJ】3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛(排列组合+乘法逆元+欧拉定理/费马小定理)


    http://www.lydsy.com/JudgeOnline/problem.php?id=3398

    以下牡牛为a,牝牛为b。

    学完排列计数后试着来写这题,“至少”一词可以给我们提示,我们可以枚举a为x头(x>1),然后算出对应的排列累计起来。

    对于x头a,首先我们先缩掉必要的k头牛(x-1)*k,然后这时可以特判可以先结束(因为单调的),然后在缩好后的x个点和n-x-(x-1)*k个点进行多重排列就行了。

    只是遇到一个问题,多重排列有个除法,又要取模的QAQ,即(a/b)%m,怎么做呢。。我只能去抱大腿。dwellings神犇说这是乘法逆元,这样转换(a*b^(phi(m)-1)) % m

    其实补补mod意义下的除法吧

    我们知道除以ab=1时,b就是a的逆元,同理,a也是b的逆元。

    在实际意义下的数的逆元就是它的倒数,而mod意义下的逆元没有倒数的说法,在这里我们要补一些概念:

    剩余系:就是mod n的所有元素,即0~n-1

    而mod意义下的加减乘都是在剩余系中完成的,例如(a+b)%c=(a%c+b%c)%c,这里的a%c和b%c就是转换到了剩余系中然后做加法,显然这是成立的。

    但是除法不同,而在剩余系中的逆元是可能出现在剩余系中的(如果不是,那么要用另一种做法,就是将这个mod拆开,这里先不阐述。。因为我不会嘛。。)

    那么我们同样用ab=1来求逆元,那么显然我们可以用乘法来做。

    例如mod15下的7*13=1,那么13就是7的逆元,7也是13的逆元。

    哈哈,那么显然了,当在剩余系n中,元素a有ax=1(mod n),且gcd(a, n)=1(即有解),那么中x就是a的逆元。

    还有一个欧拉定理(费马小定理

    a^(phi(n))=1(mod n),且a和n互质

    那么逆就是a^(phi(n)-1) mod n

    看来得去补补数论了QAQ

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%lld", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
    #define printarr1(a, b) for1(_, 1, b) cout << a[_] << '	'; cout << endl
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    inline const int max(const int &a, const int &b) { return a>b?a:b; }
    inline const int min(const int &a, const int &b) { return a<b?a:b; }
    
    const int N=100005;
    const long long MOD=5000011;
    int p[N], n, k;
    long long fastpow(long long a, long long b) {
    	long long ret=1; a%=MOD;
    	while(b) {
    		if(b&1) ret=(ret*a)%MOD;
    		a=(a*a)%MOD;
    		b>>=1;
    	}
    	return ret;
    }
    int main() {
    	read(n); read(k); p[0]=p[1]=1;
    	for1(i, 2, n) p[i]=((long long)p[i-1]*(long long)i)%MOD;
    	long long ans=1+n;
    	for1(i, 2, n) {
    		int b=n-i, x=i, y=b-(x-1)*k;
    		if(y<0) break;
    		//(a / b) % p = a * b ^ (phi(p)-1) % p
    		ans=(ans+((long long)p[x+y]*fastpow((long long)p[x]*(long long)p[y], MOD-2))%MOD)%MOD;
    	}
    	print(ans);
    	return 0;
    }
    

    Description

        约翰要带N(1≤N≤100000)只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛.牛们要站成一排.但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有K(O≤K<N)只牝牛.
        请计算一共有多少种排队的方法.所有牡牛可以看成是相同的,所有牝牛也一样.

    Input

        一行,输入两个整数N和K.

    Output

     
        一个整数,表示排队的方法数.

    Sample Input


    4 2

    Sample Output

    6
    样例说明
    6种方法分别是:牝牝牝牝,牡牝牝牝,牝牡牝牝,牝牝牡牝,牝牝牝牡,牡牝牝牡

    HINT

    Source

  • 相关阅读:
    Zabbix的前台SQL注射漏洞利用
    LeetCode OJ--Permutation Sequence *
    LeetCode OJ--Next Permutation *
    LeetCode OJ--Permutations II
    LeetCode OJ--Permutations *
    小算法-计算下一个排列
    LeetCode OJ--Gas Station**
    LeetCode OJ--Insert Interval **
    LeetCode OJ--Search Insert Position
    Ruby自动化测试(操作符的坑)
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4000820.html
Copyright © 2020-2023  润新知