原题链接
题目大意
有一个人,用小写英文字母计数,再这种计算法中,每个字母互不相同,而且从左到右都是严格递增的,每次还规定能够使用一个范围的字母,规定了长度。题目将会给我们 s s s, t t t, w ( s ≤ t ≤ 26 , 2 ≤ w ≤ t − s ) w(s\le t\le 26,2\le w\le t-s) w(s≤t≤26,2≤w≤t−s), n n n,分别代表字母开始位置,结束位置,数字长度和目前数字,要求往后输出五个连续的数字,如果没有,则尽量多输出。
解题思路
这一题虽说是排列,但却是以组合的方式解题。先来介绍一下组合(非搜索版):
原题链接:外网进不去
首先,定义一个变量
j
j
j,从最后开始,找到第一个不是从
n
n
n开始的连续递减序列里的末尾开始的,然后,再把
a
[
j
]
+
+
a[j]++
a[j]++,并在此基础上
a
[
i
]
=
a
[
i
−
1
]
+
1
a[i]=a[i-1]+1
a[i]=a[i−1]+1,直到序列变为:
n
−
l
e
n
t
h
+
1
,
n
−
l
e
n
t
h
+
2
,
.
.
.
,
n
−
2
,
n
−
1
,
n
n-lenth+1,n-lenth+2,...,n-2,n-1,n
n−lenth+1,n−lenth+2,...,n−2,n−1,n
代码结束。
如:
要求使用从
1
∼
5
1\sim 5
1∼5这五个数中选
3
3
3个组合:
初始:
1
,
2
,
3
1,2,3
1,2,3;
计算结束后,
j
=
3
j=3
j=3,得
1
,
2
,
4
1,2,4
1,2,4;
再次计算结束后,
j
=
3
j=3
j=3,得
1
,
2
,
5
1,2,5
1,2,5;
又一次计算结束后,
j
=
2
j=2
j=2,得
1
,
3
,
4
1,3,4
1,3,4;
接着,
j
=
3
j=3
j=3,得
1
,
3
,
5
1,3,5
1,3,5;
然后,
j
=
2
j=2
j=2,得
1
,
4
,
5
1,4,5
1,4,5;
……
最后,
j
=
2
j=2
j=2,得
3
,
4
,
5
3,4,5
3,4,5;
接着,
j
=
1
j=1
j=1,结束;
代码实现:
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
long long n,a[100],fact[100],m;
int main()
{
cin>>n>>m;
for(long long i=1;i<=m;i++)
a[i]=i;
while(true){
for(int j=1;j<=m;j++)
cout<<a[j];
cout<<endl;
long long i=m;
while(i>0&&a[i]==n-m+i)
i--;
a[i]++;
for(long long l=i+1;l<=m;l++)
a[l]=a[l-1]+1;
if(i==0)
break;
}
}
其实,这一题也十分类似。我们可以以题目所给的数据为初始,先将末尾加一,如果超界,再往前试。由于要求严格递增,就算是当前没有超界,结尾也有可能超界。所以如果想要判断超界,那么就得计算出结尾,并且判断是否超界。结尾公式不难推,仔细想想,就可以得到
a
(
n
)
=
a
(
j
)
+
l
e
n
t
h
−
j
a(n)=a(j)+lenth-j
a(n)=a(j)+lenth−j的计算公式,但如果运行到了这里,就说明前面一直超界,所以这个位置应该加一,所以正确判断出界的公式应为:
a
(
j
)
+
l
e
n
t
h
−
j
+
1
a(j)+lenth-j+1
a(j)+lenth−j+1,如果会超界,那
j
=
j
−
1
j=j-1
j=j−1。一直找到一个不超界的地方,如果是
1
1
1,程序就结束里,如果不是,就把这个位置加一,由于要求严格递增,所以最接近上一个数的数应该是每一位都在这个位的基础上加一(
a
(
i
)
=
a
(
i
−
1
)
+
1
a(i)=a(i-1)+1
a(i)=a(i−1)+1)。
如
2 10 5
bdfij
首先
j
=
3
j=3
j=3,可得到:
b
d
g
h
i
bdghi
bdghi;
接着
j
=
5
j=5
j=5,可得到:
b
d
g
h
j
bdghj
bdghj;
然后
j
=
4
j=4
j=4,可得到:
b
d
g
i
j
bdgij
bdgij;
再接着
j
=
3
j=3
j=3,可得到:
b
d
h
i
j
bdhij
bdhij;
最后
j
=
2
j=2
j=2,可得到:
b
e
f
g
h
befgh
befgh;
输出满了五个,程序结束。
代码实现:
#include<bits/stdc++.h>
using namespace std;
long long n,m,t;
char a[100];
int main()
{
cin>>n>>m>>t;
for(int i=1;i<=t;i++)
cin>>a[i];
for(int k=1;k<=5;k++){//之后五个
int j=t;
while(j>0&&a[j]-'a'+t-j+1>=m)//枚举j
j--;
if(j==0)//结束条件,没有更多
break;//结束
a[j]++;//在当前位置加一
for(int i=j+1;i<=t;i++)
a[i]=a[i-1]+1;//在a[j]的基础上,a[i]=a[i-1]+1
for(int i=1;i<=t;i++)
cout<<a[i];//输出
cout<<endl;
}
}
样例
输入
2 10 5
bdfij
输出
bdghi
bdghj
bdgij
bdhij
befgh