题目链接:点击打开链接
思路:
根据数据范围, 很容易确定用d[i][j]表示前i位和为j是否能组成符合要求的数字。 用path[i][j]表示下一个状态的j值, hehe[i][j]表示当前状态选了哪个数字。
特判n == 1 && s == 0。
细节参见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <ctime>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
typedef long double ld;
const double eps = 1e-6;
const double PI = acos(-1);
const int mod = 1000000000 + 7;
const int INF = 0x3f3f3f3f;
// & 0x7FFFFFFF
const int seed = 131;
const ll INF64 = ll(1e18);
const int maxn = 100;
int T,n,m,d[110][910], vis[110][910], kase = 0, sum, path[110][910], hehe[110][910];
int dp1(int i, int j) {
int& ans = d[i][j];
if(i == n+1) {
if(j == sum) return 1;
else return 0;
}
if(vis[i][j] == kase) return ans;
vis[i][j] = kase;
ans = 0;
for(int k = 0; k < 10; k++) {
if(i == 1 && k == 0) continue;
int nxt = dp1(i+1, j+k);
if(ans < nxt) {
ans = nxt;
path[i][j] = j+k;
hehe[i][j] = k;
}
}
return ans;
}
void print(int i, int j) {
if(i == n+1) return ;
printf("%d", hehe[i][j]);
print(i+1, path[i][j]);
}
int dp2(int i, int j) {
int& ans = d[i][j];
if(i == n+1) {
if(j == sum) return 1;
else return 0;
}
if(vis[i][j] == kase) return ans;
vis[i][j] = kase;
ans = 0;
for(int k = 9; k >= 0; k--) {
if(i == 1 && k == 0) continue;
int nxt = dp2(i+1, j+k);
if(ans < nxt) {
ans = nxt;
path[i][j] = j+k;
hehe[i][j] = k;
}
}
return ans;
}
int main() {
scanf("%d",&T);
while(T--) {
scanf("%d%d", &n, &sum);
if(n == 1 && sum == 0) {
printf("0 0\n");
continue;
}
++kase;
int ans1 = dp1(1, 0);
if(!ans1) {
printf("-1 -1\n");
continue;
}
print(1, 0);
printf(" ");
++kase;
int ans2 = dp2(1, 0);
print(1, 0);
printf("\n");
}
return 0;
}