permu(变态考试题)
题目描述
给定一个严格递增的序列T,求有多少个T的排列S满足:∑min(T[i],S[i])=k
输入输出格式
输入格式:
第一行两个数n,k
第二行n个数,表示T
输出格式:
一个正整数表示答案,答案对10^9+9取模
输入输出样例
输入样例#1:
5 10 1 2 3 4 5
输出样例#1:
24
说明
30%的数据n<=10
100%的数据 输入中所有数字为不超过50的正整数,k<=2500
题解:动态规划
正常的思路会想到状态压缩或暴力搜索,可以利用那个min变成普通的动归
f[i][j][k]表示前i位,还有j个数未匹配,和为k的方案数
情况1:与自己匹配,f[i+1][j][k+t[i+1]]+=f[i][j][k]
情况2:与后面的数匹配,因为严格递增,所以f[i+1][j+1][k+2*t[i+1]]+=f[i][j][k]
情况3:与前面的数匹配,再用前面的数匹配自己,f[i+1][j-1][k]+=f[i][j][k]*j*j
解释:把当前数往前匹配有j种方案,把前面的数往当前匹配有j种,根据乘法原理可知
情况4:与前面的数匹配,自己不匹配,f[i+1][j][k+t[i+1]]+=f[i][j][k]*j
解释:与前面的数匹配有j种,为什么不算后面的数,假设所有l>i且匹配了i
因为对于l,3,4情况已经算了i,所以f[l][j][k]包含了l匹配i的方案,无需重复计算
为方便定义,规定只考虑往前的匹配种数
本蒟蒻考试时完全不会,不像yzh大佬
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 long long f[51][51][2501]; 7 int Mod=1000000009; 8 int n,k,t[51]; 9 int main() 10 {int i,j,l; 11 cin>>n>>k; 12 for (i=1;i<=n;i++) 13 { 14 scanf("%d",&t[i]); 15 } 16 f[0][0][0]=1; 17 for (i=0;i<n;i++) 18 { 19 for (j=0;j<=i;j++) 20 { 21 for (l=0;l<=k;l++) 22 if (f[i][j][l]) 23 { 24 f[i+1][j][l+t[i+1]]=(f[i+1][j][l+t[i+1]]+f[i][j][l])%Mod; 25 f[i+1][j+1][l+2*t[i+1]]=(f[i+1][j+1][l+2*t[i+1]]+f[i][j][l])%Mod; 26 if (j) f[i+1][j-1][l]=(f[i+1][j-1][l]+f[i][j][l]*j*j)%Mod; 27 f[i+1][j][l+t[i+1]]=(f[i+1][j][l+t[i+1]]+f[i][j][l]*j*2)%Mod; 28 } 29 } 30 } 31 cout<<f[n][0][k]; 32 }