挑战庞果英雄会之子序列的个数

题目详情  

本题同样来自caopengcs,只要你有兴趣,每个人都可以出题(出题入口在主页右侧边栏“贡献题目”->“我要发布”内),以下是题目详情:

子序列的定义:对于一个序列a=a[1],a[2],......a[n],则非空序列a'=a[p1],a[p2]......a[pm]为a的一个子序列,其中1<=p1<p2<.....<pm<=n。

例如:4,14,2,3和14,1,2,3都为4,13,14,1,2,3的子序列。

对于给出序列a,有些子序列可能是相同的,这里只算做1个,要求输出a的不同子序列的数量。

输入: 长度为n的数组1<=n<=100,数组元素0<=a[i]<=110

输出:子序列 的个数对1000000007取余数的结果(由于答案比较大,输出Mod 1000000007的结果即可)。

函数头部:

C/C++:

  int run(cons int *a,int n);

       其实我一开始就做对了,但是由于数目太大,超过了double能表示的精度,所以最后结果一直没有对。现在几经曲折,找到一种办法。来解决数目太大的问题。

            先说算法的思想,从左到右添加子序列,第一次取最左边的一个,第二次,加入第二个,第三次加入第三个‘’‘’‘’‘’加很简单,主要是要去除相同的元素。

     我用一个数组来记录加入一个数后当前序列个数增加的数目。既这些数目是由于加了这个数才产生的。

    假设当前添加到第i个数,前面有N个不相同的子序列,那么新加了这个数后,子序列的长度会增加一倍再加1,但是其中包含了很多重复的序列,重复的序列是因为前面存在相同的数字,只要用前面子序列的长度减去这些重复的数目,得到的就是这个新添加的数产生的新的子序列数目,记做in。假设前面只要第K个数和这个i上面的数相等,那么in = N +1 - kn;如果前面还有其它相等的数,同样要减去那个位置记录的数。最后子序列的总数目等于 i1 + i2 + *+ in;

    这样思想是对的,但是要实现还差一点,因为最后的子序列数目非常大,用int不能表示,用long long也不能表示。

用double类型是能够有这个范围,但是失去了精度,不能保存个位十位百位这些低位的数。我想到可以将结果分开来存,到结果大于一个数后,就将大于的部分另外存储。但是这样运算速度太慢,失败!后来我发现其实只需要存储小于1000000007的部分就可以了,因为大于的部分最后求余的时候都是没有用的,而且运算中只要加减运算,于是结果如下:



int  run(const int *a,int n) {
 int iNum = 0;
    int iArry[100];
    for (int i = 0; i < n; i++)
    {
        iArry[i] = iNum + 1;
        for (int j = 0; j < i; j++)
        {
            if (a[i] == a[j])
            {
                iArry[i] -= iArry[j];
                if (iArry[i] < 0)
                {
                    iArry[i] += 1000000007;
                }
            }
        }
        iNum += iArry[i];
        if (iNum > 1000000007)
        {
            iNum -= 1000000007;
        }
    }
    return iNum;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值