第一题
考虑两个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);
}