UVA - 12105 Bigger is Better(DP)

Keywords: Programming iOS

Portal

First, such problems, dynamic programming of a number, are generally diverted from other residuals

Then this topic uses a more important nature of large number redundancy, that is, large numbers can be manipulated one by one to achieve the purpose of redundancy, which can be referred to Here

Method One

state transition

Set d(i,j)d(i,j)d(i,j) D (i, j) to represent the maximum number of J J J that can be spelled out with I I I matches divided by the remainder of mmm, and use string strings to represent large numbers.Since the state transitions are independent of each other, consider the brush table method and set d(i,j)d(i,j)d(i,j) d(i, j) to curcurcur cur after spelling the current digit kkk to update the unknown state from the current state:

d(i+c(k),(j∗10+k)%m)=max(d(i+c(k),(j∗10+k)%m),cur);d(i+c(k),(j*10+k)\%m)=max(d(i+c(k),(j*10+k)\%m),cur);d(i+c(k),(j∗10+k)%m)=max(d(i+c(k),(j∗10+k)%m),cur);

It's important to note that you can't use max directly here. I was wrong at first.Since strings are compared in dictionary order, that is, "111" is not "9" large, a string size comparison function needs to be written:

int cmp(string &s1,string &s2){
    if(s1.size()>s2.size()) return 1;
    if(s1.size()<s2.size()) return -1;
    if(s1==s2) return 0;
    return s1>s2?1:-1;
}

Boundary handling and final answer

Since the string is filled from the right to the left bit, that is, 0_90-90_9 of the first bit is the initial state of all other state transitions, then we enumerate them sequentially by first setting d(0,0)=0d(0,0)=0d(0,0)=0. Note when splicing below, since there is no leading 000, if the first bit is 000, start from the first bit again

At the end of the answer, it is max(d(i,0)),0 < I < n max(d(i,0)),0 \leq I \leq n max(d(i,0)),0 < I < n

Of course, you will notice that the final answer is only 000 and you cannot tell when to output 1-1_1.In fact, the initialization of 000is because 000is a special state - 000modulus of any number is 0000, that is, 0 will not be the largest if there are any other states, so we add a special judgment, when ans=0ans=0ans=0, when and only when n=6n geq 6n=6, the output will be 1000, otherwise it will be_1-1_1

Time Complexity

O(10_n_m)O(10*n*m)O(10_n_m), STL did not disappoint me - 1.8s!

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <math.h>
#include <cstdio>
#include <string>
#include <bitset>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define lowbit(x) (x&(-x))
#define mkp(x,y) make_pair(x,y)
#define mem(a,x) memset(a,x,sizeof a);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> P;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const ll INF=1e18;
const int Mod=1e9+7;
const int maxn=2e5+10;

int num[]={6, 2, 5, 5, 4, 5, 6, 3, 7, 6};
string d[110][3005];
int n,m;

int cmp(string &s1,string &s2){
    if(s1.size()>s2.size()) return 1;
    if(s1.size()<s2.size()) return -1;
    if(s1==s2) return 0;
    return s1>s2?1:-1;
}

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int kase=0;
    while(cin>>n && n){
        cin>>m;
        mem(d,0);
        d[0][0]="0";
        for(int i=0;i<=n;i++)
            for(int j=0;j<=m;j++) if(d[i][j].size())
                for(int k=0;k<10;k++){
                    char ch=k+'0';
                    string res=d[i][j];
                    if(res[0]=='0') res=ch;
                    else res+=ch;
                    if(cmp(d[i+num[k]][(j*10+k)%m],res)<0)
                        d[i+num[k]][(j*10+k)%m]=res;
                }
        string ans="0";
        for(int i=0;i<=n;i++)
            if(cmp(d[i][0],ans)>0)
                ans=d[i][0];

        cout<<"Case "<<++kase<<": ";
        if(n>=6 && ans[0]=='0'){
            cout<<"0"<<endl;
        }else if(ans[0]=='0') cout<<"-1"<<endl;
        else cout<<ans<<endl;
    }
    return 0;
}

Method 2

In fact, it's hard to imagine and to achieve, and I have to admire it after referring to the code of Teacher LRJ

Understanding this method I refer to this Blog , in great detail!Suggest a look

#include<cstdio>
#include<cstring>

using namespace std;

const int maxn = 100 + 5;
const int maxm = 3000 + 5;

int n, m, dp[maxn][maxm], p[maxn][maxm];

int needs[] = { 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 };

int main(){
    int kase = 0;
    while(scanf("%d%d", &n, &m) == 2) {
        printf("Case %d: ", ++kase);

        for(int i = 0; i <= n; i++)
            for(int j = 0; j < m; j++){
                int& ans = dp[i][j];
                ans = p[i][j] = -1;
                if (j == 0) ans = 0;
                for(int d = 9; d >= 0; d--)
                    if (i >= needs[d]){
                        int t = dp[i - needs[d]][(j * 10 + d) % m];
                        if (t >= 0 && t + 1 > ans){
                            ans = t + 1;
                            p[i][j] = d;
                        }
                }
            }

        if (p[n][0] < 0) printf("-1");
        else {
            int i = n, j = 0;
            for(int d = p[i][j]; d >= 0; d = p[i][j]){
                printf("%d", d);
                i -= needs[d];
                j = (j * 10 + d) % m;
            }
        }
        printf("\n");
    }
    return 0;
}

Posted by tomasd on Wed, 24 Jun 2020 18:21:14 -0700