UVA11125 - Arrange Some Marbles(dp)

题目链接

题目大意:给你n种不同颜色的弹珠,然后给出每种颜色的弹珠的个数,现在要求你将这些弹珠排序,要求相同颜色的部分最多3个。然后相同颜色的弹珠称为一个组,那么每个相邻的组要求长度不同,颜色也不同,然后首位的两组也要符合要求。

解题思路:这题之前是被n<3000给吓到了,后面dp还那么多状态,感觉复杂度不能过。后面看了题解才发现dp的时候会将所有的情况包括进去,所以只要dp的数组的复杂度够就行了,和n没有关系。因为这题有给弹珠的数目,所以需要记录一下每种颜色的弹珠的剩余数目,那么就是8?8?8?8.(可以用一个8进制的数来代替传4个参数)因为还要求相邻的颜色和长度不同,所以还要3?4来存放上一次是什么颜色长度是多少。麻烦的是首尾怎么办。枚举出首的组那么对应的尾也就好处理了。所以再开3?4将第一个的颜色和大小存储进去。这样复杂度就是8?8?8?8?144。注意:0的时候输出的是1.

为什么和n没有关系呢,因为题目变动的只是颜色的数目和各个颜色的个数,而我们dp的时候是将会出现的四种颜色,会出现的所有个数都包括进去了。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 4500;
const int maxs = 5;
const int maxc = 5;

int N, PS, PC;
int num[maxc];
int f[maxn][maxs][maxc][maxs][maxc];

int dp (int state, int s, int c) {

    int& ans = f[state][PS][PC][s][c];
    if (ans != -1)
        return ans;

    if (!state) {
        if (PS != s && PC != c)
            return ans = 1;
        return ans = 0;
    }

    int tmp[maxc];
    int tS = state;
    for (int i = N - 1; i >= 0; i--) {

        if (tS >= (1<<(3*i))) {
            tmp[i] = tS/(1<<(3*i));
            tS %= (1<<(3*i));
        } else
            tmp[i] = 0;
    }

    ans = 0;
    for (int i = 0; i < N; i++) {
        if (i == c)
            continue;
        for (int j = 1; j <= min(3, tmp[i]); j++) {
            if (j == s)
                continue;
            ans += dp(state - (j * (1<<(3*i))), j, i);
        }
    }
    return ans;
}

void solve () {

    scanf ("%d", &N);
    for (int i = 0; i < N; i++)
        scanf ("%d", &num[i]);

    int state = 0;
    for (int i = 0; i < N; i++)
        state += num[i] * (1<<(3*i));  

    int ans = 0;
    if (state) {
        for (int c = 0; c < N; c++)
            for (int s = 1; s <= min(num[c], 3); s++) {
                PS = s;
                PC = c;
                ans += dp(state - s * (1<<(3*c)), s, c);
            }
    } else
        ans = 1;
    printf ("%d\n", ans);
}

int main () {

    int T;
    scanf ("%d", &T);
    memset (f, -1, sizeof(f));

    while (T--) {
        solve();
    }
    return 0;
}
时间: 2024-08-28 09:27:41

UVA11125 - Arrange Some Marbles(dp)的相关文章

UVA 11481 - Arrange the Numbers(组合数学)

题目链接:11481 - Arrange the Numbers 题意:序列1-n,进行重排,问最后前m个中有k个仍然位置不变的情况数 思路:之前写过UVA 580, n个数重排,要求每个位置都不同的情况的题目,递推式为dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]) 利用这个,这题只要: k个位置C(m, k) * sum(C[n - m][i] (后面n-m个选出i个对应正确匹配) * dp[n - k - i](其余位置全都错排)} 这便是总情况数 代码:

HDU 1712 ACboy needs your help(DP)

Problem Description ACboy has N courses this term, and he plans to spend at most M days on study.Of course,the profit he will gain from different course depending on the days he spend on it.How to arrange the M days for the N courses to maximize the

【CF】38E Let&#39;s Go Rolling! (dp)

前言 这题还是有点意思的. 题意: 给你 \(n\) (\(n<=3000\)) 个弹珠,它们位于数轴上.给你弹珠的坐标 \(x_i\) 在弹珠 \(i\) 上面花费 \(C_i\) 的钱 可以使弹珠在原地不动 (\(-10^9<=x_i,C_i<=10^9\)),游戏开始时,所有的弹珠向左滚动,直到碰到定在原地不动的弹珠,其花费是其滚动的距离.总花费=开始前的花费+弹珠滚动的花费,问最小的花费是多少 题解 首先划分出阶段,,我们可以先将弹珠排序,前 \(i\) 个弹珠,最后一个固定的弹

hdu 5623 KK&#39;s Number(dp)

问题描述 我们可爱的KK有一个有趣的数学游戏:这个游戏需要两个人,有N\left(1\leq N\leq 5*{10}^{4} \right)N(1≤N≤5∗10?4??)个数,每次KK都会先拿数.每次可以拿任意多个数,直到NN个数被拿完.每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大.在这样的情况下,最终KK的得分减去对手的得分会是多少? 输入描述 第一行一个数T\left( 1\leq T\leq 10\right)T(1≤T≤10),表示数据组

Ural 1353 Milliard Vasya&#39;s Function(DP)

题目地址:Ural 1353 定义dp[i][j],表示当前位数为i位时,各位数和为j的个数. 对于第i位数来说,总可以看成在前i-1位后面加上一个0~9,所以状态转移方程就很容易出来了: dp[i][j]=dp[i][j]+dp[i][j-1]+dp[i][j-2]+.......+dp[i][j-9]: 最后统计即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <

HDU 4908 (杭电 BC #3 1002题)BestCoder Sequence(DP)

题目地址:HDU 4908 这个题是从m开始,分别往前DP和往后DP,如果比m大,就比前面+1,反之-1.这样的话,为0的点就可以与m这个数匹配成一个子串,然后左边和右边的相反数的也可以互相匹配成一个子串,然后互相的乘积最后再加上就行了.因为加入最终两边的互相匹配了,那就说明左右两边一定是偶数个,加上m就一定是奇数个,这奇数个的问题就不用担心了. 代码如下: #include <iostream> #include <stdio.h> #include <string.h&g

Sicily 1146:Lenny&#39;s Lucky Lotto(dp)

题意:给出N,M,问有多少个长度为N的整数序列,满足所有数都在[1,M]内,并且每一个数至少是前一个数的两倍.例如给出N=4, M=10, 则有4个长度为4的整数序列满足条件: [1, 2, 4, 8], [1, 2, 4, 9], [1, 2, 4, 10], [1, 2, 5, 10] 分析:可用动态规划解题,假设dp[i][j],代表满足以整数i为尾数,长度为j的序列的个数(其中每一个数至少是前一个数的两倍).那么对于整数i,dp[i][j] 等于所有dp[k][j-1]的和,其中k满足:

UVA542 - France &#39;98(dp)

UVA542 - France '98(dp) 题目链接 题目大意:之前题目意思还以为看懂了,其实没看明白,它已经把各个选手分在各自所在的区域里面,这就意味着第一次的PK的分组已经确定,而且冠军必须是从两个左右分区出来的胜利者才有机会pk冠军. 解题思路:那么从1-16这个大的区间内诞生出来的冠军可能是来自左边,也可能是右边,然后再左边右边的子区间递归找出冠军.f[i][l][r]表示l-r这个区间的胜利者是i的概率,那么假设i在区间的最左边,f[i][l][r] = Sum(f[i][l][m

HDU 4968 Improving the GPA(dp)

HDU 4968 Improving the GPA 题目链接 dp,最大最小分别dp一次,dp[i][j]表示第i个人,还有j分的情况,分数可以减掉60最为状态 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int t, avg, n; double dp1[15][405], dp2[15][405]; double get(int x) { if