poj-1989

26 篇文章 0 订阅
//144K  141MS   C++
#include <cstdio>
#include <cstring>

using namespace std;

int K;
int N;

const int MAX = 10001;

char flag[MAX];

int completeCollectionNum = 0;

int main() {
    while(scanf("%d %d", &N, &K) != EOF) {
        memset(flag, 0, sizeof(flag));
        int unAppearNum = K;
        for (int i = 1; i <= N; i++) {
            int val;
            scanf("%d", &val);
            if (flag[val]) {
            } else {
                flag[val] = 1;
                unAppearNum--;
                if (unAppearNum == 0) {
                    completeCollectionNum++;
                    memset(flag, 0, sizeof(flag));
                    unAppearNum = K;
                }
            }
        }
        printf("%d\n", completeCollectionNum+1);
    }
}

一道考智力的题,不适合我这样的庸才,直接看了后面的discuss:

证明子序列长度为至少是n当且仅当序列是这样的()()...()[],一个()是一次1..m都出现的序列,共n个。
必要性。数学归纳法。n>=1是,序列显然是()[],假设n>=k是,序列是k个()+[],如果n>=k+1,取第k个()的最后一个素,这个元素在长度为k的某个子序列中一定会用到,如果用不到就把它放到[]中去,这样做第k个()仍然是一次1..m都出现的序列,再取前一个元素,由归纳假设保证第k个()中一定有一个元素满足要求,由于n>=k+1,所以在这个元素之后必然会出现1..m的所有元素一次,所以[]=()[]'
充分性。太显然了,没什么证的。


假设有排序的个数为n,则其最短的非子序长度,可由下面方法求得。

如果存在其有包括全排序的一个最小组合,(1,2,...n),(次序不限,只要有1...n的数字就行了,也有可能有重复数字)

找到其所有这样组合。可合成()()()...()[],( 设有k个括号,[]里的元素可能为空)
则其最短的非子序长度为k+1;
原因:
长度为k的子序,都可由前k个括号里抽出一个数组成。
但对于k+1,就找不到一个组合,因为最后一个组合里少了需要的最后一个数。 

如本例子中:
14 5
1
5
3
2
5
1
3
4
4
2
5
1
2
3

首先有(1,5,3,2,5,1,3,4)(4,2,5,1,2,3)[]
故其最短非子序长度为3;

// | ... a1| | ... a2| ... |  ac|| ... | 
// 后面的| ... | 是没有完整的 1 - k  
// 统计前面出现完整的 1 - k 的个数 c , c + 1 就是答案
// 设每一个完整的1 - k 以 ai结束( 1 <= i <= c )
// 假设最后一个缺少  aj , 则无法构造 a1 a2 ... ac aj 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值