日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

组合数学学习(一)——排列组合和母函数经典习题

發布時間:2024/3/24 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 组合数学学习(一)——排列组合和母函数经典习题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

B - 排列
next_permutation

inline void read(int &x){int data = 0, w = 1;char ch = getchar();while(ch != '-' && !isdigit(ch))ch = getchar();if(ch == '-')w = -1, ch = getchar();while(isdigit(ch))data = 10 * data + ch - '0', ch = getchar();x = data * w; } void write(int x){if(x < 0)putchar('-'), x = -x;if(x > 9)write(x / 10);putchar('0' + x % 10); } const int maxn = 1024 + 5; int n, m, a[maxn];int main() {int t; read(t);while (t--) {read(n), read(m);for (int i = 1; i <= n; ++i) read(a[i]);while (m) { next_permutation(a + 1, a + n + 1); m--; }for (int i = 1; i <= n; ++i) {write(a[i]);putchar(i == n ? '\n' : ' ');}} }

C - Round Numbers
求二進制區間內0的數量大于等于1的數量的十進制數的個數
數位dp,用一個變量保存0和1的數量差,因為中途可能出現差小于0的情況,我們加上32使其大于等于0即可

const int maxn = 32 + 5; int dp[maxn][maxn << 1], a[maxn]; int f(int pos, int num, bool limit, bool lead) {if (pos == -1) return num >= 0;if (!limit && !lead && dp[pos][num + maxn] != -1) return dp[pos][num + maxn];int up = limit ? a[pos] : 1, sum = 0;for (int i = 0; i <= up; ++i) {if (lead && i == 0) sum += f(pos - 1, num, limit && i == a[pos], lead && i == 0);else sum += f(pos - 1, num + (i == 0 ? 1 : -1), limit && i == a[pos], lead && i == 0);}if (!limit && !lead) dp[pos][num + maxn] = sum;return sum; } int solve(int x) {int p = 0;while (x) {a[p++] = x % 2;x /= 2;}return f(p - 1, 0, true, true); } int main() {memset(dp, -1, sizeof(dp));int a, b; read(a), read(b);write(solve(b) - solve(a - 1)); putchar('\n'); }

D - 好題
求升序并小于給出的字符串的數量
數位dp,用變量保存當前選的字符

char str[12]; ll dp[12][30]; ll f(int pos, int ch, bool limit, bool lead) {//printf("pos = %d, ch = %d, limit = %d\n", pos, ch, limit);if (pos == -1) return ch > 0;if (!limit && dp[pos][ch] != -1) return dp[pos][ch];int up = limit ? str[pos] - 'a' + 1 : 26; ll sum = 0;//printf("%d-%d\n", limit, up);for (int i = lead ? 0 : ch + 1; i <= up; ++i) {sum += f(pos - 1, i, limit && i == up, lead && i == 0);}if (!limit) dp[pos][ch] = sum;return sum; } int main() {memset(dp, -1, sizeof(dp));while (~scanf("%s", &str)) {int n = strlen(str);bool flg = true;for (int i = 1; i < n; ++i) {if (str[i] <= str[i - 1]) {flg = false;break;}}if (!flg) { printf("0\n"); continue; }reverse(str, str + n);printf("%lld\n", f(n - 1, 0, true, true));} }

E - Number Sequence
先找規律,發現1~91\sim 919之間每次長度都加1,10~9910\sim 991099之間每次長度都加2,100~999100\sim 999100999之間每次都加3,依次類推;數的范圍從9到90到900…,公差從1到2到3…。
發現給出范圍內公差最多到5,我們暴力找到每個數在的公差的大范圍
再二分找到具體的數字

int main() {int t; scanf("%d", &t);while (t--) {ll k; scanf("%lld", &k);int d = 0, a1 = 0, sz = 9;ll sum = 0;while (true) {d++; a1 += d;ll tmp = 1ll * a1 * sz + 1ll * sz * (sz - 1) / 2 * d;if (sum + tmp < k) {sum += tmp;a1 = a1 + (sz - 1) * d; sz *= 10;continue;}int l = 0, r = 1e6;while (l != r) {int n = (l + r) >> 1;if (1ll * a1 * n + 1ll * n * (n - 1) / 2 * d >= k - sum) r = n;else l = n + 1;}ll pre = 1ll * a1 * (l - 1) + 1ll * (l - 1) * (l - 2) / 2 * d;sum += pre;k = k - sum;int cnt = 0;for (int i = 1; ; ++i) {if (1 <= i && i <= 9) cnt++;else if (10 <= i && i <= 99) cnt += 2;else if (100 <= i && i <= 999) cnt += 3;else if (1000 <= i && i <= 9999) cnt += 4;else if (10000 <= i && i <= 99999) cnt += 5;if (cnt >= k) {cnt -= k;while (i) {if (cnt == 0) {write(i % 10); putchar('\n');break;}cnt--;i /= 10;}break;}}break;}}}

F - Paths on a Grid
經典排列組合,方案數為(n+mm){n+m\choose m}(mn+m?)

int main() {ll n, m;while (~scanf("%lld%lld", &n, &m)) {if (n == 0 && m == 0) break;if (n > m) swap(n, m);double den = 1, mol = 1;for (ll i = m + 1; i <= n + m; ++i) {den *= 1.0 * i;mol *= 1.0 * (i - m);}printf("%.0f\n", den / mol);} }

G - Word Index
D - 好題 同一道題

char str[12]; ll dp[12][30]; ll f(int pos, int ch, bool limit, bool lead) {//printf("pos = %d, ch = %d, limit = %d\n", pos, ch, limit);if (pos == -1) return ch > 0;if (!limit && dp[pos][ch] != -1) return dp[pos][ch];int up = limit ? str[pos] - 'a' + 1 : 26; ll sum = 0;//printf("%d-%d\n", limit, up);for (int i = lead ? 0 : ch + 1; i <= up; ++i) {sum += f(pos - 1, i, limit && i == up, lead && i == 0);}if (!limit) dp[pos][ch] = sum;return sum; } int main() {memset(dp, -1, sizeof(dp));while (~scanf("%s", &str)) {int n = strlen(str);bool flg = true;for (int i = 1; i < n; ++i) {if (str[i] <= str[i - 1]) {flg = false;break;}}if (!flg) { printf("0\n"); continue; }reverse(str, str + n);printf("%lld\n", f(n - 1, 0, true, true));} }

H - The Last Non-zero Digit
求階乘的最后一位非0數
參考數學相關

int get_prime_factor(int n, int x) {if (!n) return 0;return n / x + get_prime_factor(n / x, x); } int g(int n, int x) {if (!n) return 0;return n / 10 + (n % 10 >= x) + g(n / 5, x); } int f(int n, int x) {if (!n) return 0;return f(n / 2, x) + g(n, x); } //2,3,7,9的循環節,其中注意若2的個數為0的話循環節第一位應該為1 int cyclic_section[][4] = {{6, 2, 4, 8}, {1, 3, 9, 7}, {1, 7, 9, 3}, {1, 9, 1, 9}}; int main() {int n, m;while (~scanf("%d%d", &n, &m)) {int cnt2 = get_prime_factor(n, 2) - get_prime_factor(n - m, 2);int cnt5 = get_prime_factor(n, 5) - get_prime_factor(n - m, 5);int cnt3 = f(n, 3) - f(n - m, 3);int cnt7 = f(n, 7) - f(n - m, 7);int cnt9 = f(n, 9) - f(n - m, 9);int ans = 1;if (cnt5 > cnt2) {printf("5\n"); continue;}if (cnt2 != cnt5) {ans *= cyclic_section[0][(cnt2 - cnt5) % 4];ans %= 10;}ans *= cyclic_section[1][cnt3 % 4]; ans %= 10;ans *= cyclic_section[2][cnt7 % 4]; ans %= 10;ans *= cyclic_section[3][cnt9 % 4]; ans %= 10;printf("%d\n", ans);} }

I - Hexadecimal Numbers
不能選已經選的字母,其他nnn字母選出mmm進行排列的方案數為AnmA_n^mAnm?
每個位置從能選的字母從大到小判斷,沒有則選0

int vis[20], ans[20]; ll c[20][10], fib[10];int main() {for (int i = 1; i <= 16; ++i) {c[i][0] = c[i][i] = 1;for (int j = 1; j < i; ++j) {c[i][j] = c[i - 1][j - 1] + c[i - 1][j];}}fib[0] = 1; for (int i = 1; i <= 7; ++i) fib[i] = fib[i - 1] * i;ll k;while (~scanf("%lld", &k)) {int cnt = 0;bool lead = true;for (int i = 8, j; i > 0; --i) {for (j = 15; j >= 1; --j) {if (vis[j]) continue;ll tmp = c[16 - cnt - 1][i - 1] * fib[i - 1];if (tmp < k) k -= tmp;else { vis[j] = true; break; }}if (!lead || j != 0) cnt++;if (j != 0) lead = false;if (j == 0 && lead) continue;printf("%c", j >= 10 ? j - 10 + 'A' : j + '0');}putchar('\n');} }

J - The Counting Problem
計算范圍內每個數出現的個數
我們枚舉每個位置,該位置把數分成三個部分,左邊的數為leftleftleft,該數字numnumnum,右邊的數為rightrightright,枚舉當前位置的數iii

cnt={{left×10len+right+1,i==numleft×10len+10len,num>i,i≠0{(left?1)×10len+right+1,num==i(left?1)×10len+10len,num>i,i=0cnt=\begin{cases}\begin{cases}left\times{10^{len}}+right+1,i==num\\left\times10^{len}+10^{len},num>i \end{cases},i\ne0\\\begin{cases}(left-1)\times10^{len}+right+1,num==i\\(left-1)\times10^{len}+10^{len},num>i \end{cases},i=0\end{cases} cnt=????????????{left×10len+right+1,i==numleft×10len+10len,num>i?,i?=0{(left?1)×10len+right+1,num==i(left?1)×10len+10len,num>i?,i=0?

int ans[10]; ll fib[10]; int solve(int x, int y) {int res = 0;for (int i = 1; i <= 9; ++i) {int l = x / fib[i - 1];int r = x - l * fib[i - 1];int rt = l % 10; l /= 10;//printf("%d - %d - %d\n", l, rt, r);if (y == 0) {if (l) {res += (l - 1) * fib[i - 1];if (rt == 0) res += r + 1;else if (rt > y) res += fib[i - 1];}}else {res += l * fib[i - 1];if (rt > y) res += fib[i - 1];else if (rt == y) res += r + 1;}if (l <= 0) break;}return res; } int main() {fib[0] = 1; for (int i = 1; i <= 9; ++i) fib[i] = fib[i - 1] * 10;int a, b;while (~scanf("%d%d", &a, &b)) {if (a == 0 && b == 0) break;if (a > b) swap(a, b);memset(ans, 0, sizeof(ans));for (int i = 0; i <= 9; ++i) {printf("%d%c", solve(b, i) - solve(a - 1, i), i == 9 ? '\n' : ' ');}} }

K - How many 0’s?
J的簡化版

ll fib[12]; ll solve(ll x) {if (x < 0) return -1;ll res = 0;for (int i = 1; i <= 12; ++i) {ll l = x / fib[i - 1];ll r = x - l * fib[i - 1];int rt = l % 10; l /= 10;if (!l) break;res += (l - 1) * fib[i - 1];if (rt) res += fib[i - 1];else res += r + 1;}return res; } int main() {fib[0] = 1; for (int i = 1; i <= 12; ++i) fib[i] = fib[i - 1] * 10;ll a, b;while (~scanf("%lld%lld", &a, &b)) {if (a == -1 && b == -1) break;if (a == 0 && b == 0) printf("1\n");else printf("%lld\n", solve(b) - solve(a - 1));} }

L - Binary Stirling Numbers
給出S(0,0)=1S(0,0)=1S(0,0)=1,其他全為0,因此答案要為1,就要考慮使n=0,m=0n=0,m=0n=0,m=0的方案數
S(n,m)=mS(n?1,m)+S(n?1,m?1)S(n,m)=mS(n-1,m)+S(n-1,m-1)S(n,m)=mS(n?1,m)+S(n?1,m?1)分奇偶討論

  • m為偶數時,S(n,m)=S(n?1,m?1)S(n,m)=S(n-1,m-1)S(n,m)=S(n?1,m?1)
  • m為奇數時,S(n,m)=S(n?1,m)+S(n?1,m?1)S(n,m)=S(n-1,m)+S(n-1,m-1)S(n,m)=S(n?1,m)+S(n?1,m?1),代入S(n?1,m?1)=S(n?2,m?2)S(n-1,m-1)=S(n-2,m-2)S(n?1,m?1)=S(n?2,m?2)變為奇數情況得到S(n,m)=S(n?1,m)+S(n?2,m?2)S(n,m)=S(n-1,m)+S(n-2,m-2)S(n,m)=S(n?1,m)+S(n?2,m?2)

n×mn\times mn×m的矩陣里,設S(n?1,m)S(n-1,m)S(n?1,m)為操作111S(n?2,m?2)S(n-2,m-2)S(n?2,m?2)為操作222,因此必須有m+12\frac{m+1}{2}2m+1?的操作222n?mn-mn?m個操作111,對m+12\frac{m+1}{2}2m+1?進行插空n?mn-mn?m得到(m+12+n?mm+12){\frac{m+1}{2}+n-m\choose \frac{m+1}{2}}(2m+1?2m+1?+n?m?)
(nm){n\choose m}(mn?)判斷奇偶性,處理n,n?m,mn,n-m,mn,n?m,m的2的因子數,如果因子數相減正好為0即為奇數

int get(int x) {int ret = 0;for (int i = 2; i <= x; i <<= 1) {ret += x / i;}return ret; } bool solve(int n, int m) {return get(n) - get(m) - get(n - m) == 0; } int main() {int t; read(t);while (t--) {int n, m; read(n); read(m);int decre = n - m, k = (m + 1) / 2;println(solve(decre + k - 1, k - 1));} }

M - Birthday Cake
差分和牛頓公式
參考數學相關

import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.math.BigInteger; import java.util.Scanner; public class Main{Scanner scan = new Scanner(System.in);BigInteger c[]=new BigInteger[110];BigInteger h[][] = new BigInteger[110][110];void getc(BigInteger n, int m) {c[1] = n;for (int i = 2; i <= m+1; i++)c[i] = c[i - 1].multiply(n.subtract(BigInteger.valueOf(i - 1))).divide(BigInteger.valueOf(i));}PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));void run() {int cas=scan.nextInt();while(cas-->0){BigInteger n =scan.nextBigInteger().add(BigInteger.ONE);int m = scan.nextInt();for (int i = 0; i <= m; i++)h[0][i] = BigInteger.valueOf(i).pow(m);for (int i = 1; i <= m; i++)for (int j = 0; j <= m - i; j++)h[i][j] = h[i - 1][j + 1].subtract(h[i - 1][j]);BigInteger ans = BigInteger.ZERO;getc(n, m);for (int i = 0; i <= m; i++)ans=ans.add(h[i][0].multiply(c[i+1]));out.println(ans);out.flush();}}public static void main(String[] args) {new Main().run();} }

N - Sum of powers
伯努利數解決等冪求和
參考數學相關

typedef long long ll; const int maxn = 20 + 3; ll gcd(ll a, ll b) {return b == 0 ? a : gcd(b, a % b); } ll lcm(ll a, ll b) {ll ret = a / gcd(a, b) * b;return ret ? ret : -ret; } struct fraction {ll a, b;fraction() {}fraction(ll x) { a = x; b = 1; }fraction(ll x, ll y) { a = x; b = y; }void deal() {if (b < 0) b = -b, a = -a;ll k = gcd(a, b);if (k < 0) k = -k;a /= k; b /= k;}fraction operator +(const fraction& rhs) const {fraction ans;ans.b = lcm(b, rhs.b);ans.a = ans.b / b * a + ans.b / rhs.b * rhs.a;ans.deal();return ans;}fraction operator -(const fraction& rhs) const {fraction ans;ans.b = lcm(b, rhs.b);ans.a = ans.b / b * a - ans.b / rhs.b * rhs.a;ans.deal();return ans;}fraction operator *(const fraction& rhs) const {fraction ans;ans.a = a * rhs.a;ans.b = b * rhs.b;ans.deal();return ans;}fraction operator /(const fraction& rhs) const {fraction ans;ans.a = a * rhs.b;ans.b = b * rhs.a;ans.deal();return ans;}void println() {printf("%lld/%lld\n", a, b);} }; fraction B[maxn]; ll C[maxn][maxn]; void init() {for (int i = 1; i < maxn; ++i) {C[i][0] = C[i][i] = 1;for (int j = 1; j < i; ++j) {C[i][j] = C[i - 1][j - 1] + C[i - 1][j];}}B[0] = fraction(1);for (int i = 1; i <= 20; ++i) {B[i] = fraction(0);for (int j = 0; j < i; ++j)B[i] = B[i] - fraction(C[i + 1][j]) * B[j];B[i] = B[i] / fraction(C[i + 1][i]);} } int n; fraction a[maxn]; int main() {init();while (~scanf("%d", &n)) {ll Lcm = 1;for (int i = 0; i <= n; ++i) {a[i] = fraction(C[n + 1][i]) * B[i] * fraction(1, n + 1);Lcm = lcm(Lcm, a[i].b);}printf("%lld ", Lcm);a[1] = a[1] + fraction(1);for (int i = 0; i <= n; ++i)printf("%lld ", Lcm / a[i].b * a[i].a);puts("0");} }

O - Ignatius and the Princess III
dfs

const int maxn = 120 + 5; int dp[maxn][maxn]; int solve(int n, int m) {if (n == 0) return 1;if (m > n) return 0;if (dp[n][m] != -1) return dp[n][m];int res = 0;for (int i = m; i <= n; ++i) {if (n - i >= i) {res += solve(n - i, i);}else if (i == n) res += solve(0, i);}return dp[n][m] = res; } int main() {memset(dp, -1, sizeof(dp));int n;while (~scanf("%d", &n)) {println(solve(n, 1));} }

P - Train Problem II
大數+卡塔蘭數經典應用

const int maxn = 100 + 5; struct Bigint {vector<int> s;Bigint() { s.clear(); }Bigint operator =(int n) {while (n) {s.push_back(n % 10);n /= 10;}return *this;}friend Bigint operator *(const Bigint& a, const int& b) {Bigint res; int k = 0;for (int i = 0; i < a.s.size(); ++i) {res.s.push_back((k + a.s[i] * b) % 10);k = (k + a.s[i] * b) / 10;}while (k) {res.s.push_back(k % 10);k /= 10;}return res;}friend Bigint operator /(const Bigint& a, const int& b) {Bigint res; int k = 0;for (int i = a.s.size() - 1; i >= 0; --i) {res.s.push_back((k * 10 + a.s[i]) / b);k = (k * 10 + a.s[i]) % b;}reverse(res.s.begin(), res.s.end());while (res.s.back() == 0) res.s.pop_back();return res; }void print() {for (int i = s.size() - 1; i >= 0; --i) {putchar(s[i] + '0');}} }; Bigint C[maxn]; int main() {C[0] = 1;for (int i = 1; i <= 100; ++i) {C[i] = C[i - 1] * (4 * i - 2);C[i] = C[i] / (i + 1);}int n; while (~scanf("%d", &n)) {C[n].print(); putchar('\n');} }

Q - 排列組合
指數型母函數解析

double fib(int n) {double res = 1.0;for (int i = 1; i <= n; ++i) {res = res * i;}return res; } double a[maxn], f[maxn], g[maxn]; int main() {int n, m;while (~scanf("%d%d", &n, &m)) {memset(f, 0, sizeof(f));memset(g, 0, sizeof(g));for (int i = 0; i < n; ++i) {scanf("%lf", &a[i]);}for (int i = 0; i <= a[0]; ++i) {f[i] = 1.0 / fib(i);}for (int i = 1; i < n; ++i) {for (int j = 0; j <= m; ++j) {for (int k = 0; k <= a[i] && j + k <= m; ++k) {g[j + k] += f[j] / fib(k);}}for (int j = 0; j <= m; ++j) {f[j] = g[j]; g[j] = 0;}}printf("%.0lf\n", f[m] * fib(m));} }

S - Factstone Benchmark
斯特靈公式n!~2πn(ne)nn!\sim\frac{\sqrt{2\pi n}}{(\frac{n}{e})^n}n!(en?)n2πn??
即為n!<22in!<2^{2^i}n!<22i,兩邊求對數log2log_2log2?12log2(2πn)?nlog2(ne)<2i,i≤24\frac{1}{2}log_2(2\pi n)\cdot nlog_2(\frac{n}{e})<2^i,i\le2421?log2?(2πn)?nlog2?(en?)<2i,i24,暴力求最大滿足n

typedef long long ll; //n! = \sqrt{2\pi n}\frac{n}{e}^n //log_2{n!} = \frac{1}{2}log_2{2\pi n}nlog_2{\frac{n}{e}} int a[]={3,5,8,12,20,34,57,98,170,300,536,966,1754,3210,5910,10944,20366,38064,71421,134480,254016};int main(){int n;while(scanf("%d",&n),n){printf("%d\n",a[(n-1960)/10]);}return 0; }

T - 找單詞
普通母函數解析

int a[maxn]; ll f[maxn], g[maxn]; int main() {int t; scanf("%d", &t);while (t--) {for (int i = 1; i <= 26; ++i) scanf("%d", &a[i]);memset(f, 0, sizeof(f));memset(g, 0, sizeof(g));for (int i = 0; i <= a[1]; ++i) {f[i] = 1;}for (int i = 2; i <= 26; ++i) {for (int j = 0; j <= 50; ++j) {for (int k = 0; k <= a[i] && i * k + j <= 50; ++k) {g[i * k + j] += f[j];}}for (int j = 0; j <= 50; ++j) {f[j] = g[j]; g[j] = 0;}}ll ans = 0;for (int i = 1; i <= 50; ++i) ans += f[i];printf("%lld\n", ans);} }

總結

以上是生活随笔為你收集整理的组合数学学习(一)——排列组合和母函数经典习题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。