把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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);
	}
}
posted @ 2021-03-21 16:26  275307894a  阅读(47)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end