题目链接:http://poj.org/problem?id=1285
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 1551 | Accepted: 522 |
Description
Input
Output
Sample Input
5 2 1 2 3 4 5 2 1 4 1 1 2 3 4 2 0 0
Sample Output
Case 1: 10 5 Case 2: 6
题意:给一串序列,求一共有多少不同组合。比如样例1,当r=2的时候,有(1,2)(1,3)(1,4)(1,5)(2,3)(2,4)(2,5)(3,4)(3,5)(4,5)一共十种组合。注意当出现重复数字的时候,如果一个组合两个数字都一样,只算一个。比如序列1,1,2 当r=2时有两个解,一个是(1,1),一个是(1,2)
思路:用dp[i][j]表示从i开始(包括i)r=j时的组合数量。 易知dp[i][j]=dp[i+1][j-1]+dp[k][j] k为从i开始第一个不等于i的数(因为dp[k][j]代表不取i,那么[i,k)这个区间内的数都一样,如果取了,就矛盾了。) 注意本题不能把数组排序后删去重复的,因为题目可能询问的很大,那么答案是11112223的可能性很大,去掉将很难处理。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[55];
unsigned long long dp[55][55];
int main()
{
int n,m,r;
int q=1;
while(scanf("%d %d",&n,&m)&&(n&&m))
{
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
dp[i][0]=1;
dp[n][1]=1;
int k;
for(int i=n-1; i>=1; i--)
{
for(int j=1; j<=n; j++)
{
dp[i][j]=dp[i+1][j-1];
for(k=i+1;k<=n;k++)
if(a[k]!=a[i])
break;
dp[i][j]+=dp[k][j];
}
}
printf("Case %d:\n",q++);
while(m--)
{
scanf("%d",&r);
printf("%llu\n",dp[1][r]);
}
}
return 0;
}