【USACO 5.5.3】Two Five

题意

  一个5*5字符矩阵,每个字符比它左面和上面的字符都要大,它可以这样转换成一个字符串:下一行接在本行行末。所以是一个长度为25的字符串(包含A~Y的字符)。把符合条件的矩阵转换成字符串后,按字典序排序并依次编号。要求编号和字符串互相转换。

题解

  刚开始就觉得以前做过很多类似这样的题了。但是它的限制条件相对来说比较多,也没有什么特殊规律。所以只好计数DP了。

  先看编号转字符串,枚举字符串开头(即一行一行地填字符矩阵),比如说“AB”开头的字符串有多少个?如果大于要求的编号的话,那么自然答案字符串的开头就是“AB”了。这个思想十分容易理解。

  字符串转编号,类似地!如果这个字符串是“AC~~~~~”,我们先加上"AB~~~~"的字符串个数,然后一直逼近,直至相同。

  好了。那么怎么统计以“AB”或者其他开头的字符串个数呢?

  搞个5维数组DP。每一维表示这一行填了多少个。那么F[5][5][5][5][5]=1了。此乃边界是也。

  具体看下代码,比较好理解啦。

  哦对对,算下时间复杂度先。O(55)*O(52)=O(57)=O(78125)

代码

/*
TASK:twofive
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int f[6][6][6][6][6], code, len[5], t[5], mode, maxr[5], maxc[5];
char cmd[2], chmat[5][5];
bool v[25];

int dp(int a, int b, int c, int d, int e, int k)
{
    int &ans = f[a][b][c][d][e];
    if (ans) return ans;
    if (!v[k]) return dp(a, b, c, d, e, k + 1);
    if (a < 5 && k > maxr[0] && k > maxc[a]) ans += dp(a+1, b, c, d, e, k+1);
    if (b < a && k > maxr[1] && k > maxc[b]) ans += dp(a, b+1, c, d, e, k+1);
    if (c < b && k > maxr[2] && k > maxc[c]) ans += dp(a, b, c+1, d, e, k+1);
    if (d < c && k > maxr[3] && k > maxc[d]) ans += dp(a, b, c, d+1, e, k+1);
    if (e < d && k > maxr[4] && k > maxc[e]) ans += dp(a, b, c, d, e+1, k+1);
    return ans;
}

int main()
{
    freopen("twofive.in", "r", stdin);
    freopen("twofive.out", "w", stdout);
    scanf("%s\n", cmd);
    memset(len, 0, sizeof(len));
    code = 0;
    memset(chmat, 0, sizeof(chmat));
    if (cmd[0] == ‘N‘) scanf("%d", &code), mode = 0;
    else
    {
        for (int i = 0; i < 5; ++i)
            for (int j = 0; j < 5; ++j)
                scanf("%c", &chmat[i][j]);
        mode = 1;
    }
    memset(v, true, sizeof(v));
    memset(maxr, -1, sizeof(maxr));
    memset(maxc, -1, sizeof(maxc));
    for (int i = 0; i < 5; ++i)
    {
        len[i] = 0;
        for (int j = 0; j < 5; ++j)
        {
            len[i]++;
            if (mode == 0)
            {
                for (int k = 0; k < 25; ++k)
                    if (v[k] && k > maxr[i] && k > maxc[j])
                    {
                        memset(f, 0, sizeof(f));
                        f[5][5][5][5][5] = 1;
                        v[k] = false;
                        maxr[i] = maxc[j] = k;
                        int tmp = dp(len[0], len[1], len[2], len[3], len[4], 0);
                        if (code <= tmp)
                        {
                            chmat[i][j] = ‘A‘ + k;
                            break;
                        }
                        else
                        {
                            v[k] = true;
                            code -= tmp;
                        }
                    }
            }
            else
            {
                for (int k = 0; k < chmat[i][j] - ‘A‘; ++k)
                    if (v[k] && k > maxr[i] && k > maxc[j])
                    {
                        memset(f, 0, sizeof(f));
                        f[5][5][5][5][5] = 1;
                        v[k] = false;
                        maxr[i] = maxc[j] = k;
                        code += dp(len[0], len[1], len[2], len[3], len[4], 0);
                        v[k] = true;
                    }
                v[chmat[i][j] - ‘A‘] = false;
            }
        }
    }
    if (mode == 0)
    {
        for (int i = 0; i < 5; ++i)
            for (int j = 0; j < 5; ++j)
                printf("%c", chmat[i][j]);
        printf("\n");
    }
    else printf("%d\n", code + 1);
    return 0;
}
时间: 2024-12-17 06:53:20

【USACO 5.5.3】Two Five的相关文章

【USACO 1.3.4】牛式

[題目描述 ] 下面是一个乘法竖式,如果用我们给定的那n个数字来取代*,可以使式子成立的话,我们就叫这个式子牛式. * * * x * * ---------- * * * * * * ---------- * * * * 数字只能取代*,当然第一位不能为0,况且给定的数字里不包括0. 注意一下在美国的学校中教的"部分乘积",第一部分乘积是第二个数的个位和第一个数的积,第二部分乘积是第二个数的十位和第一个数的乘积. 写一个程序找出所有的牛式. [格式] INPUT FORMAT: (f

【USACO 1.2.2】方块转换

[问题描述] 一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案.写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式: 1:转90度:图案按顺时针转90度. 2:转180度:图案按顺时针转180度. 3:转270度:图案按顺时针转270度. 4:反射:图案在水平方向翻转(以中央铅垂线为中心形成原图案的镜像). 5:组合:图案在水平方向翻转,然后再按照1到3之间的一种再次转换. 6:不改变:原图案不改变. 7:无效转换:无法用以上方法得到新图案. 如

【USACO 2.3.4】货币系统

[描述] 母牛们不但创建了它们自己的政府而且选择了建立了自己的货币系统.由于它们特殊的思考方式,它们对货币的数值感到好奇. 传统地,一个货币系统是由1,5,10,20 或 25,50, 和 100的单位面值组成的. 母牛想知道有多少种不同的方法来用货币系统中的货币来构造一个确定的数值. 举例来说, 使用一个货币系统 {1,2,5,10,...}产生 18单位面值的一些可能的方法是:18x1, 9x2, 8x2+2x1, 3x5+2+1,等等其它. 写一个程序来计算有多少种方法用给定的货币系统来构

【USACO 2.3.3】零数列

[题目描述] 请考虑一个由1到N(N=3, 4, 5 ... 9)的数字组成的递增数列:1 2 3 ... N. 现在请在数列中插入“+”表示加,或者“-”表示减,“ ”表示空白(例如1-2 3就等于1-23),来将每一对数字组合在一起(请不要在第一个数字前插入符号). 计算该表达式的结果并判断其值是否为0. 请你写一个程序找出所有产生和为零的长度为N的数列. [格式] PROGRAM NAME: zerosum INPUT FORMAT 单独的一行表示整数N (3 <= N <= 9). O

【USACO 2.3.5】控制公司

[题目描述] 有些公司是其他公司的部分拥有者,因为他们获得了其他公司发行的股票的一部分.例如,福特公司拥有马自达公司12%的股票.据说,如果至少满足了以下三个条件之一,公司A就可以控制公司B了: 公司A = 公司B. 公司A拥有大于50%的公司B的股票. 公司A控制K(K >= 1)个公司,记为C1, ..., CK,每个公司Ci拥有xi%的公司B的股票,并且x1+ .... + xK > 50%. 给你一个表,每行包括三个数(i,j,p):表明公司i享有公司j的p%的股票.计算所有的数对(h

【USACO 1.4.2】时钟

[题目描述] 考虑将如此安排在一个 3 x 3 行列中的九个时钟: |-------| |-------| |-------| | | | | | | | |---O | |---O | | O | | | | | | | |-------| |-------| |-------| A B C |-------| |-------| |-------| | | | | | | | O | | O | | O | | | | | | | | | | |-------| |-------| |---

【USACO 1.4.1】铺放矩形块

[描述] 给定4个矩形块,找出一个最小的封闭矩形将这4个矩形块放入,但不得相互重叠.所谓最小矩形指该矩形面积最小. 所有4个矩形块的边都与封闭矩形的边相平行,图1示出了铺放4个矩形块的6种方案.这6种方案是仅可能的基本铺放方案.因为其它方案能由基本方案通过旋转和镜像反射得到. 可能存在满足条件且有着同样面积的各种不同的封闭矩形,你应该输出所有这些封闭矩形的边长. (分类注解:这里的分类依据可以视为是不同的面积计算公式.) [格式] INPUT FORMAT: (file packrec.in)

【USACO 1.2.1】挤牛奶

[问题描述] 三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶.第一个农民在300时刻(从5点开始计时,秒为单位)给他的牛挤奶,一直到1000时刻.第二个农民在700时刻开始,在 1200时刻结束.第三个农民在1500时刻开始2100时刻结束.期间最长的至少有一个农民在挤奶的连续时间为900秒(从300时刻到1200时刻),而最长的无人挤奶的连续时间(从挤奶开始一直到挤奶结束)为300时刻(从1200时刻到1500时刻). 你的任务是编一个程序,读入一个有N个农民(1 <= N <= 5000

【USACO 3.1.5】联系

[描述] 奶牛们开始对用射电望远镜扫描牧场外的宇宙感兴趣.最近,他们注意到了一种非常奇怪的脉冲调制微波从星系的中央发射出来.他们希望知道电波是否是被某些地外生命发射出来的,还是仅仅是普通的的星星发出的. 帮助奶牛们用一个能够分析他们在文件中记下的记录的工具来找到真相.他们在寻找长度在A到B之间(含)在每天的数据文件中重复得最多的比特序列 (1 <= A <= B <= 12).他们在找那些重复得最多的比特序列.一个输入限制告诉你应输出多少频率最多的序列. 符合的序列可能会重叠,并且至少出

【USACO 3.1.6】邮票

[描述] 已知一个N枚邮票的面值集合(如,{1分,3分})和一个上限K ——表示信封上能够贴K张邮票.计算从1到M的最大连续可贴出的邮资. 例如,假设有1分和3分的邮票:你最多可以贴5张邮票.很容易贴出1到5分的邮资(用1分邮票贴就行了),接下来的邮资也不难: 6 = 3 + 3 7 = 3 + 3 + 1 8 = 3 + 3 + 1 + 1 9 = 3 + 3 + 3 10 = 3 + 3 + 3 + 1 11 = 3 + 3 + 3 + 1 + 1 12 = 3 + 3 + 3 + 3 13