C. Factorials and Powers of Two(列舉,暴力)
阿新 • • 發佈:2022-03-07
C. Factorials and Powers of Two
Tag
列舉
暴力
題目來源
Codeforces Round #774 (Div. 2)
題目大意
- 求問一個數能拆成最少多少個powerful的數字的和,powerful的數的定義為這個數要麼是2的次方,要麼是某個數的階乘,如果沒有方案,則輸出-1
解題思路
- 我們知道一個數一定能夠通過2的n次方的和加起來,比如6(110),\(6 = 2^1 + 2^2\),因此不存在輸出-1的情況
- 現在我們需要知道能否通過若干個階乘的結果來得到最優的答案,我們知道,\(15! \gt 10^{12}\),因此我們只需要不超過15的階乘的值
- 那麼需要多少個階乘呢?我們可以通過二進位制進行列舉,複雜度為\(2^{15}\)
- 原先的數減去這些個階乘的數字之後,剩下的就只需要看剩下的數二進位制中有多少個1了
AC Code
#include <bits/stdc++.h> using namespace std; #define IOS ios::sync_with_stdio(0) #define LL long long #define maxn (int)(2e6 + 10) #define FFF freopen("out", "w", stdout); LL n; int a[maxn]; int ans[maxn]; LL fac[20]; void init() { fac[0] = 1; for ( int i = 1 ; i <= 15 ; i++ ) fac[i] = fac[i-1] * i; return ; } int check(LL x ) { int cnt = 0 ; while ( x) { if( x & 1 ) cnt++; x >>= 1; } return cnt; } int main () { IOS; init(); int T ; cin >> T; for ( int cas = 1 ; cas <= T ; cas++ ) { cin >> n; int minx = check(n); for ( int i = 8 ; i <= 1 << 15 ; i+=8 ) { LL tmp = n ; int cnt = 0 ; for ( int j = 0 ; j <= 15 ; j++ ) if ( (1 << j) & i ) { cnt++; tmp -= fac[j]; } if ( tmp < 0 ) break; minx = min(minx, cnt + check(tmp)); } ans[cas] = minx; } for ( int i = 1 ; i <= T ; i++ ) cout << ans[i] << endl; }