zoukankan      html  css  js  c++  java
  • 2020杭电HDU-6831多校第六场Fragrant numbers(区间DP打表)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6831
    CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/107890254

    Problem Description
    Many people love numbers, and some have a penchant for specific numbers. Nowadays in popular culture, (1145141919) is a very fragrant number, and many people want to represent all other numbers with this number.

    Let S be an infinite string of ("1145141919") infinitely stitched together as "(114514191911451419191145141919...)".

    Take a prefix T of S , you can insert '(' , ')' , '+' or '∗' to T to form a new string T′, and then let the value of T′ be val(T′) according to ordinary rules. (You can insert any number of operators, even 0. But need to ensure that the inserted operators form legitimate operations)

    Now for a number N, please calculate the minimum length of T that can make val(T′)=N. For example, when N=520, the minimum length of 6 (pick the first 6 characters 114514 and insert operators to make T′=1+1+4+514 , then we have val(T′)=520 )

    If no such T exists, output −1.

    Input
    There are multiple test cases.

    The first line with a number t indicates the number of test cases.

    For each test case, one integer N per line indicates an inquiry.
    (1≤t≤30)
    (1≤N≤5000)

    Output
    Output t lines.
    One integer per line indicates the corresponding answer.

    Sample Input
    3
    520
    1
    2
    Sample Output
    6
    1
    2

    题目大意:给你一个字符串(s=1145141919),它可以无限循环下去,现在你要选择一个前缀并在其中添加括号,加号,乘号使得这个前缀能够构成数字n,问你这个最小的前缀是多长。

    emmm,机房除我都是群神仙 QAQ。。。本来看了看数据5000,然后觉得字符串的要取的长度可能达到几千。。。然后就有点崩,最后大佬们说只需要十几就OK了。。。学到了...犹豫就会败北!要冲一发,莽一发,要敢于尝试,可以先取个长度在long long承受范围内的也就差不多15左右,然后开始打表。但蒟蒻的我连打表都不会QAQ

    这玩意儿究竟要怎么打表呢?我们考虑到有括号的存在,那么对于两个区间(a[l-mid],a[mid+1][r])一定可以变成(a[l][mid]*a[mid+1][r])(a[l][mid]+a[mid+1][r]),我们可以拿一个前缀为3的来做个实验,那么可以得到(1+13,1*13,11+3,11*3,(1+1)*3,(1+1)+3,1*(1*3),1+(1*3),1*1+3...),可以看出来,左边和右边确实可以组成左乘右和左加右的形式。而左边有可能也是由这种变化得来,右边也有可能是由这种变化得来,那么我们应该要想到区间DP了,枚举中点,对左右两边进行状态转移,那么就可以得到在每个长度下左右两边的状态。

    理论上是OK的,现在就是想想要怎么写了,这个是个区间DP,那么我们肯定要枚举区间长度,枚举左端点,得出右端点,枚举中点,枚举(a[l][mid],a[mid+1][r])的状态,那么emmm,似乎好像也就这些了,至于(a[l][mid],a[mid+1][r])的状态,我们可以用个(vector)来保存,那么就可以得到如下区间DP的代码:

    for (int i=2; i<=15; i++) 
    	for (int l=1; l+i-1<=15; l++) {
    		int r=l+i-1;
    		for (int mid=l; mid<=r; mid++) 
    			for (auto x:dp[l][mid]) 
    				for (auto y:dp[mid+1][r]) {
    					if (x+y<=5000 && !vis[l][r][x+y]) {
    						dp[l][r].push_back(x+y);
    						vis[l][r][x+y]=1;
    					}
    					if (x*y<=5000 && !vis[l][r][x*y]) {
    						dp[l][r].push_back(x*y);
    						vis[l][r][x*y]=1;
    					}
    				}
    	}
    

    现在就是要考虑一下初始化了,只需要初始化长度为1的吗?我们看(1+13,1*13),很显然,(13)这个数字不可能是通过转移过来的,他就是个初始状态!!!所以,我们要将所有区间的的初始状态都记录下来,那么也就可以得到:

    for (int i=1; i<=15; i++) {
    	for (int j=i; j<=15; j++) {
    		ll p=get_num(i,j);
    		if (p>5000) continue;
    		dp[i][j].push_back(p);
    		vis[i][j][p]=1;
    	}
    }
    

    于是我们就可以愉快地得到一个AC代码了^ _ ^
    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define debug1 printf("@!$@$@!
    ")
    #define debug2(x) printf("%d
    ",x )
    typedef long long ll;
    const int mac=50;
    
    int a[mac],ans[5050];
    vector<ll>dp[50][50];
    bool vis[50][50][5010];
    
    ll get_num(int l,int r)
    {
        ll ans=0;
        for (int i=l; i<=r; i++)
            ans=ans*10+a[i];
        return ans; 
    }
    
    int main(int argc, char const *argv[])
    {
        string s="1145141919";
        s+=s;
        int len=s.length();
        for (int i=0; i<len; i++)
            a[i+1]=s[i]-'0';
        for (int i=1; i<=15; i++){
            for (int j=i; j<=15; j++){
                ll p=get_num(i,j);
                if (p>5000) continue;
                dp[i][j].push_back(p);
                vis[i][j][p]=1;
            }
        }
        for (int i=2; i<=15; i++){
            for (int l=1; l+i-1<=15; l++){
                int r=l+i-1;
                for (int mid=l; mid<=r; mid++){
                    for (auto x:dp[l][mid]){
                        for (auto y:dp[mid+1][r]){
                            if (x+y<=5000 && !vis[l][r][x+y]){
                                dp[l][r].push_back(x+y);
                                vis[l][r][x+y]=1;
                            }
                            if (x*y<=5000 && !vis[l][r][x*y]){
                                dp[l][r].push_back(x*y);
                                vis[l][r][x*y]=1;
                            }
                        }
                    }
                }
            }
        }
        for (int i=1; i<=15; i++){
            for (auto x:dp[1][i]){
                //debug2(x);
                if (x<=5000 && !ans[x]) ans[x]=i;
            }
        }//debug1;
        int t;
        scanf ("%d",&t);
        while (t--){
            int n;
            scanf ("%d",&n);
            if (ans[n]) printf("%d
    ",ans[n]);
            else printf("-1
    ");
        }
        return 0;
    }
    
  • 相关阅读:
    Sonar系列:IDEA集成SonarLint(二)
    Jenkins 安装部署全过程
    使用Docker搭建Sonarqube
    Sonar系列:SonarQube+SonarScanner 最全安装步骤(一)
    微信小程序反编译解包教程
    一张图告诉你,如何攻击Java Web应用
    windows server2019共享文件配额报错The quota limit is 10240.00 MB and the current usage is 10213.39 MB (99% of limit)的处理
    jenkins使用ssh remote插件执行shell后无法退出的问题处理
    基于docker镜像centos:7 镜像制作自定义的centos及tomcat/php/nginx镜像
    centos7.9环境基于docker和pipeline构建jenkins的ci平台
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13461891.html
Copyright © 2011-2022 走看看