NOIP2006P3 Jam的计数法 题解

(题目描述略)

本题题意为求给定长度为 w 的数列的后五个 t-s 的组合计数(字典序,可能不存在)。

对于一个给定的数列 a[0 .. w-1],求其下一个字典序的 t-s 组合算法如下:

  1. 求出 t-s 组合的上界(末状态),记为 up 数组;
  2. 从右向左查询最大的下标 i (0 ≤ i ≤ w-1) 使得 a[i] < up[i];
  3. a[i] := a[i] + 1,从左向右 a[j] := a[j-1] + 1 (i+1 ≤ j ≤ w-1)。

算法分析:我们可以发现,第一步求出的 i 下标表示 a[i+1 .. w-1] 是一个长度为 w-i-1 的最后一个组合,且 a[i .. n-1] 是一个长度为 w-i 的非末组合。这样,我们可以不改变 a[0 .. i-1],而对 a[i .. n-1] 求其下一个组合。

因为以 a[i] 为起始的组合已经完成,所以其构造方法必然是将 a[i] 换成 a[i]+1,构造出以 a[i]+1 为起始的第一个组合。其方法与全排列有异曲同工之妙。

代码如下:

#include"iostream"
#include"stdio.h"
using namespace std;
char number[30],up[30];
int main()
{
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    int i,t,w;
    scanf("%*d %d %d",&t,&w);
    for(int i=0;i<w;i++)
        cin>>number[i];
    up[w-1]='a'+t-1;
    for(int i=w-2;i>=0;i--)
        up[i]=up[i+1]-1;
    for(int step=0;step<5;step++)
    {
        for(i=w-1;(i>=0)&&(number[i]==up[i]);i--);
        if(i<0)
            break;
        for(++number[i++];i<w;i++)
            number[i]=number[i-1]+1;
        for(int i=0;i<w;i++)
            cout<<number[i];
        printf("\n");
    }
    return 0;
}

时间复杂度:O(w)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值