思路:
- 遇到阶层,他是比2的腻方还要增长地特别快, 超过1e12 只需要 n=15
- 而且他是要每一个数都是不同的, 因此可以 直接压状dp, 存 阶层可以组合出来的数
- 然后利用二进制的特性,可以组合成任意的数, 来补一下没有组合出来的数字即可.
- 然后 t是很小的, 在枚举每一个组合出来的数, 只有3e4的大小, 来看哪一个的ans小.
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 2000005 // 1e9 long long tmp; long long val[M]; struct dian{ long long val; int num; }dp[M]; void init(){ val[1]=1; for(ri i=2;i<=14;i++) { val[i]=val[i-1]*i; } for(ri i=1;i<=14;i++) { dp[(1<<(i-1))].val=val[i]; dp[(1<<(i-1))].num=1; } for(ri i=1;i<(1<<14);i++) { for(ri j=1;j<=14;j++) { if(i&(1<<(j-1))) { dp[i].val=dp[i^(1<<(j-1))].val+val[j]; dp[i].num=dp[i^(1<<(j-1))].num+1; } } } } long long n,m; int T; int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); init(); cin>>T; while(T--) { cin>>n; int ans=1e9; for(ri i=0;i<(1<<14);i++) { int tmp=0; long long a=n; if(dp[i].val<=n) { a-=dp[i].val; tmp+=dp[i].num; while(a) { if(a&1) tmp++; a>>=1; } ans=min(ans,tmp); } } cout<<ans<<"\n"; } return 0; }
后记:
- 遇到阶层他是增长地特别快的,常数特别特别小. 和压状,暴力联系在一起