Password Attacker

题意就是给 M 个关键字,组合成 N 字符长度的结果,每一个关键字都必须在 N 位的字符中出现,有多少种可能结果。

范围 1 ≤ M ≤ N ≤ 100.

举例假设 M = 3(key = 3, 7, 5)  N = 4 位字符长度

结果可以为3577, 3557, 7353, 5735.

下面的结果是不合法的

1357 // 1 没有在key中,不是合法关键字

3355 // 7 是关键字,但是结果中没有出现

357 // 结果必须是一个4位长度

思路1:

设立状态dp(i, j)表示在 M 个关键字中取前 i 个不同关键字,组成长度为 j . 所有结果总和

划分子问题

1. i == j 时候, 取前 i 个Key组成长度为 i ,结果为

2. i < j 时候,考虑dp(i-1, k),选去第 i 个元素j-k次,第i个元素与前i-1个元素不同,把这j-k个第i个元素插入到已有长度k的序列中,就可以转移到dp(i, j)

3. i > j, 不考虑

那么对于2,如何插入?

已有的 k 个元素有 k+1 个位置可以进行插入,问题就是把 j-k 个元素插入到 k+1 个桶中有多少种结果?

表示第 i 个桶,那么问题就等价于的所有非负整数解。

我们把两边同时加上k+1,变成 的所有正整数解。

相当于给j+1个1,插入隔板把它们分到k+1个桶中,每个桶要保证至少有一个元素,所以一共有 j 个可以提供插入隔板的位置,总共有k+1个桶,所以需要在这 j 个空隙中选择出k个位置插入隔板就成k+1个桶。

答案为

最后的2,也就等于 

最后的答案就是dp(m, n)

源码如下:

#include <bits/stdc++.h>
using namespace std; typedef long long int64; const int64 M = 1000000007LL;
const int maxn = 105;
int64 C[maxn][maxn];
int64 dp[maxn][maxn]; void getCombination() {
int n = maxn;
for (int i = 1; i <= n; i++)
C[i][0] = C[i][i] = 1LL; for (int i = 2; i <= n; i++)
for (int j = 1; j <= i; j++)
C[i][j] = (C[i-1][j-1] % M + C[i-1][j] % M) % M;
} int main() { getCombination();
int t, m, n, cas = 1;
scanf("%d", &t);
while ( t-- ) {
scanf("%d%d", &m, &n);
// init
memset(dp, 0LL, sizeof(dp));
for (int i = 1; i <= n; i++) dp[1][i] = 1;
for (int i = 2; i <= n; i++) dp[i][i] = (dp[i-1][i-1] * (int64)i) % M; for (int i = 2; i <= m; i++)
for (int j = i+1; j <= n; j++)
for (int k = i-1; k <= j-1; k++)
dp[i][j] = (dp[i][j] + (C[j][k] * dp[i-1][k]) % M) % M; printf("Case #%d: %lld\n", cas++, dp[m][n]);
}
return 0;
}

思路2:

qqz大神,dp(i, j)表示从 M 个元素中随机选取 i 个不同的元素组成 j 的长度的所有结果

划分子问题

1. i == j, dp(i, i) 随机从 M 个元素选取 i 个元素的全排列,为

2. i == 1, dp(1, j) 表示从 M 个元素中随机选取一个重复 j 次,结果为 M

3. i < j , ,

和的第一部分表示在dp(i-1, j-1)基础上,从剩下的M-i+1个数中取1个放到最后组成dp(i, j). 和的第二部分表示从已经选出的i个元素中挑1个放到最后。

最后的答案就是dp(m, n)

源码如下:

#include <bits/stdc++.h>
using namespace std; using int64 = long long;
const int64 M = 1000000007LL; int64 dp[105][105], A[105][105]; void initA() { for (int i = 1; i <= 100; i++) {
A[i][0] = 1;
for (int j = 1; j <= i; j++)
A[i][j] = ((i-j+1) * A[i][j-1]) % M;
}
} int m, n; int64 f(int i, int j) {
if (dp[i][j] != -1) return dp[i][j];
if (i == j) return dp[i][j] = A[m][i];
else return dp[i][j] = (((m-i+1) * f(i-1, j-1)) % M + (i * f(i, j-1)) % M ) % M;
} int main() {
freopen("A-large-practice.in", "r", stdin);
freopen("a_out.txt", "w", stdout);
int t, cas = 1;
initA();
scanf("%d", &t);
while (t--) {
scanf("%d%d", &m, &n);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
dp[i][j] = -1;
for (int i = 1; i <= n; i++) dp[1][i] = m;
printf("Case #%d: %lld\n", cas++, f(m ,n));
}
return 0;
}

【DP】组合数字的更多相关文章

  1. n全排列输出和 n个数的组合(数字范围a~b)

    n全排列输出: int WPermutation(int num, bool bRepeat) num表示num全排列 bRepeat标志是否产生重复元素的序列. int Permutation(in ...

  2. hdu 4945 2048 (dp+组合的数目)

    2048 Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submi ...

  3. #DP# ----- OpenJudge数字组合

    OpenJudge 2985:数字组合 总时间限制:1000ms  内存限制: 65536kB 描述 有n个正整数,找出其中和为t(t也是正整数)的可能的组合方式.如:n=5,5个数分别为1,2,3, ...

  4. ZOJ-3380 Patchouli’s Spell Cards DP, 组合计数

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3380 题意:有m种不同的元素,每种元素都有n种不同的相位,现在假 ...

  5. 3.29省选模拟赛 除法与取模 dp+组合计数

    LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采 ...

  6. CF 258B Little Elephant and Elections [dp+组合]

    给出1,2,3...m 任取7个互不同样的数a1,a2,a3,a4,a5,a6,a7 一个数的幸运度是数位上4或7的个数 比方244.470幸运度是2. 44434,7276727.4747,7474 ...

  7. bzoj3622已经没有什么好害怕的了 dp+组合+容斥(?)

    3622: 已经没有什么好害怕的了 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1033  Solved: 480[Submit][Status][ ...

  8. 数位dp——奏响数字数位的美妙乐章

    数位dp:处理数字数位关系的一种dp方式. 一般的题目特征十分明显: 1.一般和数字本身有很大关系. 2.一般求数字在区间L,R中的一些信息 3.L,R一般很大,通常能达到long long级别. d ...

  9. HihoCoder 1075 开锁魔法III(概率DP+组合)

    描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它 ...

随机推荐

  1. [lucene系列笔记1]lucene6的安装与配置(Windows系统)

    lucene是一个java开源的高效全文检索工具包,最近做项目要用到,把学习的过程记录一下. 第一步:下载安装jdk 1.首先从官网下载jdk(下载之前先查看你的电脑是多少位操作系统,如果是32就下载 ...

  2. HDU 4831 Scenic Popularity

    Scenic Popularity Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  3. .NET MVC TempData、ViewData、ViewBag

    说明: 原文作者贤新 原文地址:http://www.cnblogs.com/chenxinblogs/p/4852813.html ViewData和ViewBag主要用于将数据从控制器中传递到视图 ...

  4. javascript:history.go()和History.back()的区别

    http://www.mikebai.com/Article/2009-11/757.html

  5. php入门,配置wampserver

    wamp安装过程中将网站的根目录设置在www目录下,这里记录如何定义自己的根目录,以便以后需要是查看 1.启动wampserver,左键选择apache下的httpd.conf,将文件中Documen ...

  6. C++基础-01

    指针 - 指针的基本操作间接引用指针所指向的对象 - 机器一般按字节寻址,所以能够独立分配的最小空间是1字节,也就是说指针指向的 最小空间为1字节.特别地,对于bool变量,虽然实际需要的是1bit, ...

  7. Android开发学习---sharedpreference的使用

    在前面文章中,为了使数据回显,使用的技术思路是,首先,将数据持久化写到ROM或者SDCard中,其中name和password以":"分隔;然后,将数据记取出来,再用split方法 ...

  8. jQuery Mobile 表单基础

    jQuery Mobile 会自动为 HTML 表单添加优异的便于触控的外观. jQuery Mobile 表单结构 jQuery Mobile 使用 CSS 来设置 HTML 表单元素的样式,以使其 ...

  9. 把vim当做golang的IDE

    开始决定丢弃鼠标,所以准备用vim了. 那么在vim里面如何搭建golang环境呢? git盛行之下,搭建vim环境是如此简单. 而且vim搭建好了之后,基本上跟IDE没有差别. 高亮.自动补全.自动 ...

  10. Android Studio线下版和线上版都使用正式签名脚本(保证keysore签名文件和项目在同级目录),不用再因为繁琐的发正式版而烦恼

    场景:调用微信等第三方应用时如果生成的版本不是正式签名的可能会调用失败,使用如下脚本不用再为繁琐的发正式签名版而烦恼 app项目中的build.gradle追加如下代码: //使用正式签名脚本(保证k ...