qzezoj 1887 狐狸的谜语
题面传送门
就这道题我打了一个小时我太菜了。
首先这道题爆搜不可取算了吧。
然后其实这道题可以dp
因为乘法和加法不同所以分开来算。
先算乘法,定义\(f_{i,j,k}\)为\([i,j]\)区间内组成\(k\)值的最小操作数。这个区间\(dp\)就可以了。复杂度\(O(n^2T)\)
然后考虑加法,同样也是一样的.复杂度\(O(n^2T^2)\)
code:
#include<cstdio>
#include<cstring>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
#define l(x) x<<1
#define r(x) x<<1|1
#define N 200039
#define ll long long
#define ui unsigned int
using namespace std;
int n,m,k,T,ans,head,now;
int f[23][23][309],dp[23][309];
char s[23];
I int calc(int x,int y){int ans=0;for(int i=x;i<=y;i++){ans=ans*10+s[i]-'0';if(ans>T)return 1e8;}return ans;}
int main(){
register int i,j,k,h;
freopen("puzzle.in","r",stdin);
freopen("puzzle.out","w",stdout);
while(1){
scanf("%s",s+1);n=strlen(s+1);scanf("%d",&T);if(T<0) break;memset(f,0x3f,sizeof(f));memset(dp,0x3f,sizeof(dp));
for(i=1;i<=n;i++){
for(j=i;j<=n;j++){
now=calc(i,j);if(now<1e8) f[i][j][now]=0;
for(k=j-1;k>=i;k--){
now=calc(k+1,j);if(!now) {f[i][j][0]=min(f[i][j-1][0],1);continue;}
for(h=0;h*now<=T;h++) f[i][j][h*now]=min(f[i][k][h]+1,f[i][j][h*now]);
}
}
}dp[0][0]=0;
for(i=1;i<=n;i++){
for(j=0;j<=T;j++){
for(k=1;k<=i;k++){
for(h=0;h<=j;h++)dp[i][j]=min(dp[i][j],dp[k-1][h]+f[k][i][j-h]+1);
}
}
}
printf("%d\n",(dp[n][T]>=1e9?0:dp[n][T])-1);
}
}