UVa 12105 Bigger is Better (DP)

题意:用不超过 n 根火柴,组成一个尽可能大的数。

析:很明显的一个DP题,首先不难想到这个dp[i][j] 表示前 i 根火柴,所能拼出的取模 m 为 j 的数,状态转移方程也很好写,

dp[i][j] ==> dp[i+c[k]][(j*10+k)%m] 其中 k 为在后面添加的数,c 数组是用的火柴数,这个方程没问题,就是效率有点低,

因为有一个高精度问题,可以用Java来实现,也能够AC的。

第二种方法就是换一个表示方法,不过确实不太容易想到。dp[i][j] 表示用最多 i 根火柴,取模 m 的数的最大位数。毕竟位数越大,数越大。

状态转移方程也是和上面差不多就是变成位数了而已。

代码如下:

import java.math.BigInteger;
import java.util.*;

public class Main{
	public static final int maxn = 100 + 10;
	public static final int maxm = 3000 + 10;
	public static BigInteger[][] ans;
	public static int[] c;

	public static BigInteger solve(int n, int m){
		for(int i = 0; i <= n; ++i)
			for(int j = 0; j < m; ++j)
				ans[i][j] = BigInteger.valueOf(-1);

		ans[0][0] = BigInteger.ZERO;
		BigInteger res = BigInteger.valueOf(-1);
		for(int i = 0; i <= n; ++i){
			for(int j = 0; j < m; ++j){
				if(ans[i][j].equals(BigInteger.valueOf(-1)))  continue;
				for(int k = 0; k < 10; ++k){
					if(i +c[k] > n)  continue;
					ans[i+c[k]][(j*10+k)%m] = ans[i+c[k]][(j*10+k)%m].max(ans[i][j].multiply(BigInteger.valueOf(10)).add(BigInteger.valueOf(k)));
				}
			}
			if(i > 1 && res.compareTo(ans[i][0]) < 0)  res = ans[i][0];
		}
		return res;
	}

	public static void main(String []args){
		c = new int[15];
		ans = new BigInteger[maxn][maxm];
		c[0] = 6;  c[1] = 2;  c[2] = 5;  c[3] = 5;
		c[4] = 4;  c[5] = 5;  c[6] = 6;  c[7] = 3;
		c[8] = 7;  c[9] = 6;
		Scanner cin = new Scanner(System.in);
		int kase = 0;
		while(cin.hasNext()){
			int n = cin.nextInt();
			if(0 == n)  break;
			int m = cin.nextInt();
			System.out.println("Case " + (++kase) +": " + solve(n, m));
		}
		cin.close();
	}
}

第二种方法:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#define debug() puts("++++");
#define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define freopenr freopen("in.txt", "r", stdin)
#define freopenw freopen("out.txt", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const double inf = 0x3f3f3f3f3f3f;
const double PI = acos(-1.0);
const double eps = 1e-5;
const int maxn = 2600 + 10;
const int mod = 1e6;
const int dr[] = {-1, 0, 1, 0};
const int dc[] = {0, 1, 0, -1};
const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
int n, m;
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline bool is_in(int r, int c){
  return r >= 0 && r < n && c >= 0 && c < m;
}
int dp[110][3010], p[110][3010];
const int c[] = { 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 };

int main(){
  int kase = 0;
  while(scanf("%d %d", &n, &m) == 2 && n){
    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)  ans = 0;
        for(int k = 9; k >= 0; --k) if(i >= c[k]){
          int t = dp[i-c[k]][(j*10+k)%m] + 1;
          if(t > 0 && t > ans){
            ans = t;
            p[i][j] = k;
          }
        }
      }

      if(dp[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 -= c[d];
          j = (j*10 + d) % m;
        }
      }
      printf("\n");
  }
  return 0;
}
时间: 2024-10-07 06:39:40

UVa 12105 Bigger is Better (DP)的相关文章

UVA 12105 - Bigger is Better(DP+高精度)

题目链接:12105 - Bigger is Better 题意:一些火柴,问你能组成整除m最大的数字是多少. 思路:dp[i][j]表示用i根火柴,组成%m余数为j的最大数字,末尾多一个数字k的状态就是dp[i + num[k]][(j * 10 + k) % m],由于最多可能50位数,所以要用高精度. 注意一个优化点,由于高精度的计算上只需要乘10+k,常规的高精度乘法复杂度还是有点高会超时,所以用数组去模拟,每次*10 + k的时候就往后多一位即可. 代码: #include <stdi

Uva 10131-Is Bigger Smarter?(DP)

题目链接:点击打开链接 DAG(有向无环图)上的最长路+打印路径 建图很简单,对于两点 a b, 能够由a到b的条件是w[a]<w[b]&&s[a]>s[b] 注意是有向图. 设dp[i] 为以i为起点的最长路的长度,dp[i]= max(dp[i],dp[j]+1)  枚举j (j是和i相连的点) #include <algorithm> #include <iostream> #include <cstring> #include <

UVA - 10131Is Bigger Smarter?(DAG上的DP)

题目:UVA - 10131Is Bigger Smarter? (DAG) 题目大意:给出一群大象的体重和IQ.要求挑选最多的大象,组成一个序列.严格的体重递增,IQ递减的序列.输出最多的大象数目和这些大象的序列(当中一种就能够). 解题思路:DAG上的DP.和之前的一篇相似.uva437 - The Tower of Babylon(DAG上的DP).就是将每两仅仅大象满足上面的序列要求的形成一条有向边. 之后就是DAG上的DP.然后再路径输出. 代码: #include <cstdio>

UVA 10131 Is Bigger Smarter?(DP最长上升子序列)

Description Question 1: Is Bigger Smarter? The Problem Some people think that the bigger an elephant is, the smarter it is. To disprove this, you want to take the data on a collection of elephants and put as large a subset of this data as possible in

uva 12186 Another Crisis 树形dp

// uva 12186 Another Crisis 树形dp // // 对于一个节点u,有k个子节点,则至少有c = (k * T - 1) / 100 + 1才能 // 发信,即c / k >= T / 100,则 c 的值为 k * T /100,上取整变成上式 // 将所有的子节点d从小到大排序,取前c个就是d[u]的值 // 紫书上的一题,之前看了好久好久,觉得挺好的,然而一直没做,今天就来 // 体验体验,挺好的一题,注意一下,如果一个节点是叶节点,直接return 1就好 //

UVA 1399 - Puzzle(AC自动机+DP)

UVA 1399 - Puzzle 题目链接 题意:给定一些字符串,求一个最长的不在包含这些子串的字符串,如果可以无限长输出No 思路:建ACM自动机,把不可走结点标记构造出来,然后在这个状态图上进行dp找出最长路径即可,至于无限长的情况,只要在dp前进行一次dfs判有没有环即可 代码: #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include &

UVA 1558 - Number Game(博弈dp)

UVA 1558 - Number Game 题目链接 题意:20之内的数字,每次可以选一个数字,然后它的倍数,还有其他已选数的倍数组合的数都不能再选,谁先不能选数谁就输了,问赢的方法 思路:利用dp记忆化去求解,要输出方案就枚举第一步即可,状态转移过程中,选中一个数字,相应的变化写成一个函数,然后就是普通的博弈问题了,必胜态之后必有必败态,必败态之后全是必胜态 代码: #include <stdio.h> #include <string.h> const int N = 105

uva 417 - Word Index(数位dp)

题目连接:uva 417 - Word Index 题目大意:按照题目中的要求,为字符串编号,现在给出字符串,问说编号为多少,注意字符串必须为递增的,否则编号为0. 解题思路:其实就是算说比给定字符串小并且满足递增的串由多少个.dp[i][j]表示第i个位为j满足比给定字符串小并且满足递增的串. dp[i][j]=∑k=0j?1dp[i?1][k]. 注意每次要处理边界的情况,并且最后要加上自身串.并且在处理边界的时候dp[i][0]要被赋值为1,代表前i个为空的情况. #include <cs

UVA 10641 - Barisal Stadium(DP + 几何)

题目链接:10641 - Barisal Stadium 题意:逆时针给定n个点,在给m个灯,每个灯有一个花费,要求最小花费使得所有边能被灯照到 思路:用向量叉积判断向量的顺逆时针关系,从而预处理出每个灯能照到的边,然后由于n个点是环的,所以可以直接扩大两倍,dp时候去枚举起点即可 状态为dp[i]表示现在照到i条边之前的边全部照亮需要的最小花费 代码: #include <stdio.h> #include <string.h> const double eps = 1e-6;