《文章》陆游
文章本天成,妙手偶得之。
粹然无疵瑕,岂复须人为。
君看古彝器,巧拙两无施。
汉最近先秦,固已殊淳漓。
胡部何为者,豪竹杂哀丝。
后夔不复作,千载谁与期?
I. Space Station
大佬题解
上述题解写的非常棒!思路层层递进,而且马蜂好评
暴力:首先将原数组排序,然后dfs枚举选择顺序,如果当前和已经≥50\ge50≥50即可利用阶乘算出方案数,复杂度不可算
记忆化搜索:这里就牵扯到如何记忆化搜索?
正解非常巧妙,由于aia_iai的范围很小,这里只记录每个值出现的次数,这个信息已经足够还原原数组的必要信息。
最巧妙的是hash记忆化,当所有数剩下的个数相同时,方案数相同。这里把记录次数的数组进行hash,那么就完成了记忆化!!!
如果想到上面这些,还不行仍然TLE 怎么卡都卡不过去Q-Q
注意到如果ai=0a_i=0ai=0我们什么时候都可以选他,也就是它的选择不被约束,由此我们可以先将0剔除出来,最后直接算0对答案的贡献。
我们的选择是一个排序,只需要把这些0插到选择的过程中即可,最终答案需要乘以(cnt+1)×(cnt+2)×⋯×n(cnt+1)×(cnt+2)×\dots×n(cnt+1)×(cnt+2)×⋯×n
cnt是非零数的个数
#include<unordered_map>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=100010,mod=1e9+7;
const ull P=131;
int n;
int a[55];
ll fact[N];
unordered_map<ull,ll> dp;
void init()
{fact[0]=1;for(int i=1;i<=100000;i++) fact[i]=fact[i-1]*i%mod;
}
ll dfs(int u,int now)
{if(!u) return 1;if(now>=50) return fact[u];ull hash=0;for(int i=50;i;i--) hash=hash*P+a[i];if(dp[hash]) return dp[hash];ll res=0;for(int i=1;i<=now;i++){if(!a[i]) continue;a[i]--;res=(res+(a[i]+1)*dfs(u-1,now+i)%mod)%mod;a[i]++;}return dp[hash]=res;
}
int main()
{init();int now;cin>>n>>now;int cnt0=0,cnt1=0;for(int i=1;i<=n;i++){int x;cin>>x;if(!x) cnt0++;else a[x]++,cnt1++;}ll ans=dfs(cnt1,now);for(int i=n;i>=cnt1+1;i--)ans=(ans*i)%mod;cout<<ans<<'\n';return 0;
}
第一次见hash记忆化,非常巧妙!!!菜就多练, 要不然训练总挂机
要加油哦~