题意:
给出一个数字,要把这个数字分成尽量少的含有61的数。
题解:
首先对于n>=6161的数,可以得出一个结论,肯定能分成***61 61**这样的形式。那么对于小于6161的数可以考虑用完全背包,中途记录状态就好了。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> #define B(x) (1<<(x)) using namespace std; typedef long long ll; typedef unsigned long long ull; void cmax(int& a, int b){ if (b>a)a = b; } void cmin(int& a, int b){ if (b<a)a = b; } void cmax(ll& a, ll b){ if (b>a)a = b; } void cmin(ll& a, ll b){ if (b<a)a = b; } void add(int& a, int b, int mod){ a = (a + b) % mod; } void add(ll& a, ll b, ll mod){ a = (a + b) % mod; } const int oo = 0x3f3f3f3f; const ll OO = 0x3f3f3f3f3f3f3f3f; const ll MOD = 1000000007; const double eps = 1e-9; const int maxn = 6200; int dp[maxn]; int pre[maxn]; vector<int>num, ans; void Init(){ for (int i = 0; i <= 99; i++){ num.push_back(i * 100 + 61); if (i <= 61) num.push_back(61 * 100 + i); } for (int i = 0; i <= 9; i++){ for (int j = 0; j <= 9; j++){ num.push_back(i * 1000 + 61 * 10 + j); } } } bool had61(int n){ int u, v; u = n % 10; while (n){ v = n % 10; if (v == 6 && u == 1) return true; n /= 10; u = v; } return false; } int main(){ //freopen("E:\\read.txt","r",stdin); int T, n, W, a, b; Init(); scanf("%d", &T); while (T--){ scanf("%d", &W); if (had61(W)){ printf("1 %d\n", W); continue; } if (W >= 6161){ for (a = 6100; a <= 6199; a++){ b = W - a; if (b % 10 == 1 && b / 10 % 10 == 6) break; } printf("2 %d %d\n", a, b); continue; } n = num.size(); memset(dp, 0x3f, sizeof dp); memset(pre, -1, sizeof pre); dp[0] = 0; for (int i = 0; i < n; i++){ for (int j = num[i]; j <= W; j++){ if (dp[j]>dp[j - num[i]] + 1){ dp[j] = dp[j - num[i]] + 1; pre[j] = j - num[i]; } } } if (dp[W] == oo) printf("0\n"); else{ ans.clear(); int u, v; u = W; while (pre[u] != -1){ v = pre[u]; ans.push_back(u - v); u = v; } n = ans.size(); printf("%d", ans.size()); for (int i = 0; i < n; i++) printf(" %d", ans[i]); puts(""); } } return 0; } /* 1000 789456132 */