UVA 10581 - Partitioning for fun and profit(数论递推)

10581 - Partitioning for fun and profit

题目链接

题意:给定m, n,表示分配给n个格子,分配m个数字进去,每个格子最少1,并且序列要是递增的,问第k个字典序的序列是什么

思路:先利用dp打出表,dp[i][j][k]表示第i个数,尾巴为j,总和剩下k的情况,写一个记忆化求出,之后在这个数组基础上,从左往右枚举要放那个数字合适,合适的就放进去并且输出,注意最后一个数字要单独输出。

代码:

#include <cstdio>
#include <cstring>

typedef long long LL;
int t, M, n, vis[15][225][225];
LL k, dp[15][225][225];

LL DP(int now, int tail, int m) {
    LL &ans = dp[now][tail][m];
    if (vis[now][tail][m]) return ans;
    vis[now][tail][m] = 1;
    ans = 0;
    if (now == n) return ans = 1;
    if (now == n - 1) {
	if (m >= tail)
	    return ans = DP(now + 1, m, 0);
	return ans = 0;
    }
    for (int i = tail; i <= m - (n - now - 1); i++)
	ans += DP(now + 1, i, m - i);
    return ans;
}

void solve(LL k) {
    int v = 1;
    for (int i = 1; i < n; i++) {
	for (int j = v; j <= M - (n - i); j++) {
	    if (k > dp[i][j][M - j]) k -= dp[i][j][M - j];
	    else {
		M -= j;
		v = j;
		printf("%d\n", j);
		break;
	    }
	}
    }
    printf("%d\n", M);
}

int main() {
    scanf("%d", &t);
    while (t--) {
	memset(vis, 0, sizeof(vis));
	scanf("%d%d%lld", &M, &n, &k);
	DP(0, 1, M);
	solve(k);
    }
    return 0;
}

UVA 10581 - Partitioning for fun and profit(数论递推)

时间: 2024-08-05 11:12:50

UVA 10581 - Partitioning for fun and profit(数论递推)的相关文章

uva 10581 - Partitioning for fun and profit(记忆化搜索+数论)

题目链接:uva 10581 - Partitioning for fun and profit 题目大意:给定m,n,k,将m分解成n份,然后按照每份的个数排定字典序,并且划分时要求ai?1≤ai,然后输出字典序排在k位的划分方法. 解题思路:因为有ai?1≤ai的条件,所以先记忆化搜索处理出组合情况dp[i][j][s]表示第i位为j,并且剩余的未划分数为s的总数为dp[i][j][s],然后就是枚举每一位上的值,判断序列的位置即可. #include <cstdio> #include

UVA 1350 - Pinary(数论+递推)

题目链接:1350 - Pinary 题意:二进制数,不能有连续的1,给定第n个数字,输出相应的二进制数 思路:先是递推,求出由n位组成的数字中有几个满足条件 dp[i] = dp[i - 1] + dp[i - 2],考虑最后一位放0和倒1位放0的情况. 然后用一个sum[i]记录满足<=i位一共的情况 接着利用二分找到给定的n > sum[i - 1],i的最大值,这个就是所求的答案的最高位. 因为如果这位放1,那么就会一共多sum[i - 1] + 1个数,那么就还需要添加n - (su

HDU 4944 FSF’s game(数论+递推)

#include <cstdio> #include <cstring> typedef unsigned long long ll; const ll MOD = (1ULL<<32); const int N = 500001; int t, n; ll ans[N], frc[N]; void init() { for (ll i = 1; i < N; i++) { for (ll j = i; j < N; j += i) { ll tmp = j

LUOGU 1984: [SDOI2008]烧水问题 数论递推

title LUOGU 1984 Description: 把总质量为 1 kg 的水分装在 n 个杯子里,每杯水的质量均为 (1/n)kg,初始温度均为0℃.现需要把每一杯水都烧开.我们可以对任意一杯水进行加热.把一杯水的温度升高 t℃ 所需的能量为 (4200 * t/n) J,其中,"J"是能量单位"焦耳".如果一旦某杯水的温度达到 100℃ ,那么这杯水的温度就不能再继续升高,此时我们认为这杯水已经被烧开.显然地,如果直接把水一杯一杯地烧开,所需的总能量为

uva 10328 - Coin Toss 投硬币(dp递推,大数)

题意:抛出n次硬币(有顺序),求至少k个以上的连续正面的情况的种数. 思路:转换成求抛n个硬币,至多k-1个连续的情况种数,用所有可能出现的情况种数减去至多k-1个的情况,就得到答案了.此题涉及大数加减. 分析: (1)假设n=k,那么只有一种情况. (2)假设n=k+1,那么有3种情况,包含k个的两种,k+1个的一种. (3)假设k=1,那么只有无正面这一种的情况不能被考虑,其他都能算,那么就是(1<<n)-1种.(n个硬币有2^n种结果) (4)其他情况考虑递推.先把问题的规模降低,最小就

uva 11584 Partitioning by Palindromes 线性dp

// uva 11584 Partitioning by Palindromes 线性dp // // 题目意思是将一个字符串划分成尽量少的回文串 // // f[i]表示前i个字符能化成最少的回文串的数目 // // f[i] = min(f[i],f[j-1] + 1(j到i是回文串)) // // 这道题还是挺简单的,继续练 #include <algorithm> #include <bitset> #include <cassert> #include <

UVA 10773 Back to Intermediate Math(数论)

题目链接:Back to Intermediate Math 题意:两种过河方式,一种笔直过河,一种最快过河,求两种时间差 只要计算出两种时间,笔直过河的速度等于两个速度分量的合速度,最快就等于船速度,求出差即可. 代码: #include <stdio.h> #include <string.h> #include <math.h> int t, d, v, u; int main() { int cas = 0; scanf("%d", &

UVa 11584 Partitioning by Palindromes

/*---UVa 11584 Partitioning by Palindromes --用dp[i]表示前i个字母划分成最小回文串的个数,则有dp[i]=min{dp[j]+1}s[j+1...i]是一个回文串,状态O(n)个 每次有O(n)个决策,而判断是否是回文串复杂度O(n),这样总的复杂度O(n^3).如果事先预处理标记一下s[i...j]是否构成 回文串,这样总的复杂度O(n^2).标记s[i...j]是否构成回文串,用vis[i][j](i<=j)来标记,if s[i]!=s[j]

UVa 11583 Partitioning by Palindromes

 Description Problem H: Partitioning by Palindromes We say a sequence of characters is a palindrome if it is the same written forwards and backwards. For example, 'racecar' is a palindrome, but 'fastcar' is not. A partition of a sequence of charact