8.11 模拟

第一题
考虑两个n位的十进制正整数A和B,都没有前导0。我们需要找到两个最近的靠近A的n位数(第一个比A大或与A相等,第二个严格比A小),使得它们的十进制表示是B中所有数字的某个排列。

比如说,假如A=3022并且B=1232,用B的数字我们可以获得以下的4位数字:1223, 1232, 1322, 2123, 2132, 2213, 2231, 2312, 2321, 3122, 3212和3221。最小的比A大或者和A相等的数,且用B中的数字组成的是3122,并且最大的严格比A小的数是2321。如果A=1232而且B=3022,可能的数字是2023, 2032, 2203, 2230, 2302, 2320, 3022, 3202和3220。在用B中数字组成的数中,最小的比A大或与A相等的数是2023,没有比A小的数。

对于给定的A和B,写一个程序closest找到这些“最靠近A”的数字,或者判断它们中的一个不存在。

Input
输入文件closest.in包含2行:
第1行为一个正整数A。
第1行为一个正整数B。
(A,B均为n位的正整数)

Output
输出文件closest.out共有2行。
第一行:最小的不比A小的n位数,没有前导0,包含B中的所有字符,以某一顺序排列。如果这样的数不存在,那么输出0。
第二行:最大的比A小的n位数,没有前导0,包含B中的所有字符,以某一顺序排列。如果这样的数不存在,那么输出0。

第一题特别难系列
分析
一道非常神奇的DFS
剪枝能剪掉一大堆时间复杂度
具体就是DFS的时候按照正常思路DFS(绕口令。。)

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int k[10],i,n;
char a[101],b[101],c[101];
bool pre,ok;
void bm(int dep,char vec)
{
    int i;
    if (dep>n)
    {
        for (i=0;i<=n;i++)
        {
            printf("%c",c[i]);
            c[i]=0;
        }
        ok=1;
    }
    if (ok) return;
    for (i=0;i<=9;i++)
    if (k[i]!=0&&(pre||i>=vec-48))
    {
        if (i==0&&dep==0) continue;
        if (i>vec-48) pre=1;
        k[i]--;
        c[dep]=i+48;
        bm(dep+1,a[dep+1]);
        k[i]++;
    }
}
void sm(int dep,char vec)
{
    int i;
    if (dep>n&&pre==1)
    {
        for (i=0;i<=n;i++)
        {
            printf("%c",c[i]);
            c[i]=0;
        }
        ok=1;
    }
    if (ok||dep>n&&pre==0) return;
    for (i=9;i>=0;i--)
    if (k[i]!=0&&(pre||i<=vec-48))
    {
        if (i==0&&dep==0) continue;
        if (i<vec-48) pre=1;
        k[i]--;
        c[dep]=i+48;
        sm(dep+1,a[dep+1]);
        k[i]++;
        pre=0;
    }
}
int main()
{
    scanf("%s",&a);
    scanf("%s",&b);
    n=strlen(a)-1;
    for (i=0;i<=n;i++)
    k[b[i]-48]++;
    bm(0,a[0]);
    if (!ok)
    printf("%d",0);
    printf("\n");
    pre=0;
    ok=0;
    sm(0,a[0]);
    if (!ok)
    printf("%d",0);
}

第二题
给出一个由小写字母组成的字符串。你的任务是找出其最长的出现至少两次的子串的长度。这些重复出现的子串可以重叠(参见样例2)。

Input
输入文件ygas.in第一行包含该字符串。数据保证该字符串非空,由小写字母组成,且其长度不超过100。

Output
输出文件ygas.out包含一个数代表至少出现两次的最长子串的长度。

分析
水题!时限还TM2000MS
直接三重for套进去枚举一串的开头,二串的开头,和串的共同长度就行了

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char s[101];
int i,j,k,l,n,ma;
int main()
{
    scanf("%s",&s);
    n=strlen(s);
    for (k=1;k<=n-1;k++)
    for (i=0;i<=n-k+1;i++)
    {
        for (j=i+1;j<=n-k+1;j++)
        {
            for (l=i;l<=i+k-1;l++)
            if (s[l]!=s[l+(j-i)])
            break;
            if (l==i+k)
            ma=max(ma,k);
            if (ma==k) break;
        }
        if (ma==k) break;
    }
    printf("%d",ma);
}

第三题
为了进行一种游戏,现决定搭造一些平板,而各个平板的地址已经选定。基于最普遍的认识,没有任何支持物的平板不可能漂浮在空中。说的更精确些,任意一平板的两端必需有支柱或者它在另一块平板上。
你会得到各个平板在坐标系中的坐标(如左下图)。每一块平板的坐标都是由它的高度(与地板间的垂直距离)和它的水平方位(开始和结束)决定的。每个支柱都距它支撑的平板的边缘半个单位(如右下图)。
算出支持所有平板的支柱的总长度。
这里写图片描述
Input
输入文件platforme.in第一行包括1个整数N,1 ≤ N ≤ 100,即平板的总数。
接下来的N行每行都是一块平板的坐标,是相应的Y,X1和 X2。即高度和水平的边缘坐标。所有的数都是不大于10000的正整数且满足X2 > X1+1(也可这样理解,每一块平板的长度至少为2)。
输入保证任意两块平板间没有重叠部分。

Output
输出文件platforme.out要撑起所有平板所需的支柱的总长度。

分析
讲道理这题炒鸡水
我暴力都能0MS
不知道时限10000MS有何意义
首先将这些板按高度从小到大排序,然后依次判断,把其高度覆盖进记录这块的高度数组中
然后两头的数组值被高度减去即是该平板所用的柱子长

#include <iostream>
#include <cstdio>
using namespace std;
int n,y,x1,x2,a[10001],b[10001],c[10001],k[10001];
int i,j,su;
void qs(int l,int r)
{
    int i=l,j=r,t,mid=a[(l+r)/2];
    if (l>=r) return;
    do
    {
        while (a[i]<mid) i++;
        while (a[j]>mid) j--;
        if (i<=j)
        {
            t=a[i];a[i]=a[j];a[j]=t;
            t=b[i];b[i]=b[j];b[j]=t;
            t=c[i];c[i]=c[j];c[j]=t;
            i++;j--;
        }
    }
    while (i<=j);
    qs(i,r);
    qs(l,j);
}
int main()
{
    scanf("%d",&n);
    for (i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
        c[i]-=1;
    }
    qs(1,n);
    for (i=1;i<=n;i++)
    {
        su+=a[i]-k[b[i]]+a[i]-k[c[i]];
        for (j=b[i];j<=c[i];j++)
        k[j]=a[i];
    }
    printf("%d",su);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值