题意
有n个题目,每个题目都有一个难度,从里面选出k个难度不同的题目。
赛时思路
dp[i][j]表示选出的最后一个题的题目难度为i,已选出题数为j时的方案数,num[i]表示难度为i的题目个数, d p ( i + 1 , j ) = ( ∑ k = j − 1 i d p ( k , j − 1 ) ) ∗ n u m ( i ) dp(i+1,j)=\displaystyle \left( \sum_{k=j-1}^i dp(k,j-1) \right)*num(i) dp(i+1,j)=⎝⎛k=j−1∑idp(k,j−1)⎠⎞∗num(i),可通过记录中间量将时间复杂度降为n方。
其它思路
- 思路1:dp[i][j]表示已从前i种不同的题中选出j个不同的题的方法数,dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*num[i]。
- 思路2:k看成背包空间,然后当01背包做。
#include <iostream>
#include <cstdio>
using namespace std;
const long long mod= 998244353;
int n,k,a[1005];
long long dp[1005][1005],num[1005],sum[1005];
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
num[a[i]]++;
}
for(int i=1;i<=n;i++)
dp[i][1]=num[i];
for(int i=2;i<=n;i++)//f i j
{
for(int j=2;j<=i;j++)
{
long long ans=0;
sum[j]=(sum[j]+dp[i-1][j-1])%mod;
dp[i][j]=ans*num[i]%mod;
dp[i][j]=sum[j]*num[i]%mod;
}
}
long long ac=0;
for(int i=k;i<=n;i++)
ac=(ac+dp[i][k])%mod;
cout<<ac;
return 0;
}