【ZOJ】3841 Card (搜索+组合数学(重复元素的全排列)

来源:互联网 发布:怎样发淘宝链接给好友 编辑:程序博客网 时间:2024/06/05 12:07

题目大意:一副牌除掉大小王,然后有一些已经形成了序列,让你算剩下的牌能组合出多少种比给的序列小的组合。

思路:搜索,分这个位置相同或者小于,假如放一个小于的,则剩下的就是全排列

只不过这边的全排列是相同元素的全排列。

所采取的是位置的选择的排列方式。

比如1112233这个所有的情况就是c(7,3)*c(4,2)*c(2,2)

题目wa了很多发。

题目需要注意,是严格小于,等于是不行的。

另外就是涉及到剩的张数比给的少的情况。

这边直接给数据让大家测试吧,ps:是抄别人的。

Input:
KKKKQQQQJJJJ10101010999988887777666655554444
K
AA22334455667788991010JJKKK
KAA22334455667788991010JJQK
KKKKJJJJQQQQ1010101099998888777766665555444433332222AAAA
AA22334455667788991010JJKKQQ
KKKJJJJQQQQ1010101099998888777766665555444433332222AAAA

Output:
34650
944696453
5
596617684
0
5
1
#define _CRT_SECURE_NO_WARNINGS#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define mod 1000000007int a[15];char str[60];long long ans = 0;long long c[60][60];void init(){for (int i = 0; i < 60;i++)c[i][0] = c[i][i] = 1;for (int i = 2; i < 60;i++)for (int j = 1; j < i; j++)c[i][j] = (c[i - 1][j] + c[i - 1][j - 1])%mod;}long long gao(int sum){long long ans = 1;for (int i = 1; i < 14; i++){ans = (ans*c[sum][a[i]])%mod;sum -= a[i];}return ans;}void dfs(int cur, int sum){if (!str[cur]){return;}if (sum == 0){ans++;return;}int k = str[cur] - 48;for (int i = 1; i<k; i++){if (a[i]>0){a[i]--;ans = (ans + (gao(sum-1)) % mod) % mod;a[i]++;}}if (a[k]>0){a[k]--;dfs(cur + 1, sum - 1);}}int main(){init();while (~scanf("%s", str)){int len = strlen(str);int j = 0;for (int i = 1; i < 14; i++)a[i] = 4;for (int i = 0; i < len; i++){if (str[i] == 'A'){str[j++] = 1 + 48;a[1]--;}elseif (str[i] == '1'){str[j++] = 10 + 48;a[10]--;}elseif (str[i] == 'J'){str[j++] = 11 + 48;a[11]--;}elseif (str[i] == 'Q'){str[j++] = 12 + 48;a[12]--;}elseif (str[i] == 'K'){str[j++] = 13 + 48;a[13]--;}elseif (str[i] == '0')continue;else{str[j++] = str[i];a[str[i] - 48]--;}}str[j] = 0;int sum = 0;for (int i = 1; i < 14; i++)sum += a[i];ans = 0;if (sum != 0)dfs(0, sum);printf("%lld\n", ans);}return 0;}


0 0
原创粉丝点击