令res[i][j][0]表示数字和为i,数字平方和为j的可能性,要么为0要么为1,;res[i][j][1]表示至少有多少位数字。
res[i][j][0]=res[i-k][j-k*k] ? 1 : 0;(1<=k<=9 , 1<=i<=900,1<=j<=8100)
res[i][j][1]=min(res[i][j],res[i-k][j-k*k]+1);
然后根据res[i][j][1]寻找最优解
需要预处理一下,不然可能TLE,之前没有预处理TLE了n次。。。。。。。
#include<iostream> #include<cstdio> #include<cstring> #include<time.h> using namespace std; #define MAX 1234567890 int dp[910][8110][2],res[101]; inline int min(int a,int b) { return a < b ? a : b; } int work() { int i,j,k; memset(dp,0,sizeof(dp)); dp[0][0][0]=1; for(i=1;i<=900;i++) for(j=1;j<=8100;j++) dp[i][j][1]=MAX; for(k=1;k<10;k++) for(i=k;i<=900;i++) for(j=k*k;j<=8100;j++) if(dp[i-k][j-k*k][0]) { dp[i][j][0]=1; dp[i][j][1]=min(dp[i-k][j-k*k][1]+1,dp[i][j][1]); } return 0; } int GetRes(int n,int m) { int i,j,k,count=0; i=n; j=m; while(i>0 && j>0) { for(k=1;k<10;k++) if(i-k>=0 && j-k*k>=0 && dp[i-k][j-k*k][0] && dp[i][j][1]==dp[i-k][j-k*k][1]+1) { res[count++]=k; i=i-k; j=j-k*k; break; } } return count-1; } int main() { int i,m,n,N,count; work(); scanf("%d",&N); while(N--) { scanf("%d %d",&n,&m); if(n>900 || m>8100) { printf("No solution\n"); continue; } if(dp[n][m][0]==0 || dp[n][m][1]>100) { printf("No solution\n"); continue; } count=GetRes(n,m); for(i=0;i<=count;i++)printf("%d",res[i]); printf("\n"); } return 0; }