Fragrant numbers(dfs爆搜+區間dp+stoi)
阿新 • • 發佈:2020-08-13
題意:給出一個以 "1145141919 " 無限迴圈的字串,可以在合適的位置新增 ' + ' , ' * ' 和 ' ( ' , ' ) ' 將其轉換為表示式進行運算,給了一個n,問最少需要前幾個字元來構成n?
題解:\(dfs\)爆搜+區間dp:\(dp[l][r]\)記錄字串\(l\)到\(r\)之間可以產生的數,用\(set\)型別來自動去重,具體見程式碼:
AC_Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long longll; 4 typedef long double ld; 5 #define endl '\n' 6 const int inf=0x3f3f3f3f; 7 const int maxn=1e5+10; 8 9 10 string st=" 11451419191145141919"; //注意前面一個空格,因為我們區間的下標是從1開始的 11 int ans[maxn]; 12 set<int>dp[20][20]; 13 14 void dfs(int l,int r){ 15 if( dp[l][r].size() ) return ; //dp[l][r].size()不為0說明已經存入了資料了16 int len=r-l+1; 17 if( len<=4 ){ //如果大於4了就一定大於題目所給的5000了必須拆開,小於等於4可以不用拆開 18 int num=stoi(st.substr(l,r-l+1));//stoi:把字串化成十進位制 19 if( num<=5000 ) dp[l][r].insert(num); 20 } 21 for(int i=l;i<r;i++){ 22 dfs(l,i); 23 dfs(i+1,r); 24 for(int x:dp[l][i]){25 for(int y:dp[i+1][r]){ 26 if( x+y<=5000 ) dp[l][r].insert(x+y); 27 if( x*y<=5000 ) dp[l][r].insert(x*y); 28 } 29 } 30 } 31 } 32 33 void init(){ 34 memset(ans,-1,sizeof(ans)); 35 for(int i=1;i<=11;i++){ 36 dfs(1,i); 37 for(int x:dp[1][i]){ 38 if( ans[x]==-1 ) ans[x]=i; 39 } 40 } 41 } 42 43 set<int>num; 44 int main() 45 { 46 init(); 47 // 註釋掉的部分遍歷一下發現前11位就可以到5000了dfs完全可以AC,如果前11位都組不成的數字,以後跟不可能了,因為只有加法和乘法數字只會變大了 48 // for(int i=1;i<=11;i++){ 49 // for(int x:dp[1][i] ){ 50 // num.insert(x); 51 // } 52 // } 53 // 54 // for( auto &x:num){ 55 // cout<<x<<endl; 56 // } 57 58 int T; cin>>T; 59 while( T-- ){ 60 int n; cin>>n; 61 cout<<ans[n]<<endl; 62 } 63 return 0; 64 }