UOJ #9 vfk的数据 排序
题目
描述
UOJ上,由于一群人开心的在hack着,有的题的测试数据都有 10000 组了!
为了处理这些数据,vfk决定把这道题所有输入数据都弄出来,每个数据给个编号,比如 uoj1.in , uoj2.in 。
这些编号是随机的,可以不连续,比如三组数据分别叫 uoj1.in , uoj100.in , uoj2014.in 。
输入数据的文件名一定是:题目名 + 数据编号 + “.in.in”。
vfk要你把这些输入文件按数据编号进行排序,之后用在线仙人球嵌套动态网络路径剖分优化的分支定界贪心剪枝启发式迭代加深人工智能搜索决策算法解决问题。
input
8
dajiahaowoshiyangli9.in
dajiahaowoshiyangli5.in
dajiahaowoshiyangli2.in
dajiahaowoshiyangli1.in
dajiahaowoshiyangli3.in
dajiahaowoshiyangli7.in
dajiahaowoshiyangli6.in
dajiahaowoshiyangli8.in
output
dajiahaowoshiyangli1.in
dajiahaowoshiyangli2.in
dajiahaowoshiyangli3.in
dajiahaowoshiyangli5.in
dajiahaowoshiyangli6.in
dajiahaowoshiyangli7.in
dajiahaowoshiyangli8.in
dajiahaowoshiyangli9.in
限制与约定
测试点编号 | nn的规模 |
---|---|
1
~ | n≤100 |
6
~ | n≤10000 |
保证每个字符串的长度小于等于 100 .
时间限制:
1s
空间限制:
256MB
分析
直接排序。
第一关键字:长度;
第二关键字:字典序;
时间复杂度为
O(nLlogn)
。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=32768;
const int L=128;
int n;
struct P
{
char s[L];
int len;
}p[N];
inline int operator < (P pa,P pb)
{
return pa.len!=pb.len?pa.len<pb.len:strcmp(pa.s,pb.s)<0;
}
int main(void)
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%s",p[i].s),p[i].len=strlen(p[i].s);
sort(p+1,p+n+1);
for (int i=1;i<=n;i++) printf("%s\n",p[i].s);
return 0;
}
其实数据范围加强,也是可以做的.
还是快排,优化字符串的比较方法.
对于两个字符串,我们先预处理处前缀Hash值,然后二分长度找到不相同的第一位。
时间复杂度优化为
O(nlognlogL)
.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ulint;
const int N=32768;
const int L=128;
const int M=257;
int n;
struct P
{
char s[L];
int len;
ulint h[L];
inline void calc(void);
}p[N];
inline void P::calc(void)
{
ulint mtp=1; h[1]=s[1];
for (int i=2;i<=len;i++)
{
mtp=mtp*M;
h[i]=h[i-1]+mtp*s[i];
}
}
inline int operator < (P pa,P pb)
{
if (pa.len!=pb.len) return pa.len<pb.len;
int l=0,r=pa.len,mid;
for (;l<=r;)
{
mid=l+r>>1;
pa.h[mid]==pb.h[mid]?l=mid+1:r=mid-1;
}
return pa.s[r+1]<pb.s[r+1];
}
int main(void)
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",&p[i].s[1]);
p[i].len=strlen(&p[i].s[1]);
p[i].calc();
}
sort(p+1,p+n+1);
for (int i=1;i<=n;i++) printf("%s\n",&p[i].s[1]);
return 0;
}
另外还可以使用Trie.
O(NL)
.
小结
较大的数字的处理方法:
①用字符串存储,注意不要误用int;
②注意比较数的大小的时候,首先要比较长度,然后再按字典序比较;
③涉及运算时要用数组倒着存,高精度模拟;
排序的常用方法:
①冒泡排序:针对小数据;
②快速排序/sort:普通数据;
③基数排序/Trie树排序:当元素的种类很少时考虑使用;
不要忽略方法①和方法③.
关于字典序比较的实现:
①strcmp,字典序逐位比较,
O(L)
②若要多次比较,可以考虑预处理出前缀Hash值,然后二分+Hash找最多的相同位,再比较下一位.
预处理
O(L)
,比较
O(logL)
.