题意:给出一个以 "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 long ll; 4 typedef long double ld; 5 #define endl ' ' 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 }