[UOJ 300][CTSC2017]吉夫特-扩展Lucas定理

来源:互联网 发布:江苏运时数据招聘 编辑:程序博客网 时间:2024/05/18 20:05

吉夫特

简单的题目,既是礼物,也是毒药。

B 君设计了一道简单的题目,准备作为 gift 送给大家。

输入一个长度为 n 的数列 a1,a2,,an

问有多少个长度大于等于 2 的不上升的子序列 ab1,ab2,,abk 满足

ki=2(abi1abi)mod2=(ab1ab2)×(ab2ab3)××(abk1abk)mod2>0

输出这个个数对 1000000007取模的结果。

G 君看到题目后,为大家解释了一些基本概念。

我们选择任意多个整数 bibi 满足
1b1<b2<<bk1<bkn

我们称 ab1,ab2,,abk 是 aa 的一个子序列。

如果这个子序列同时还满足
ab1ab2abk1abk

我们称这个子序列是不上升的。

组合数 (nm) 是从 n 个互不相同的元素中取 m 个元素的方案数,具体计算方法如下:

(nm)=n!m!(nm)!=n×(n1)××2×1(m×(m1)××2×1)((nm)×(nm1)××2×1)

这里要特别注意,因为我们只考虑不上升子序列,所以在求组合数的过程中,一定满足 n≥mn≥m,也就是(abi1abi)中一定有 abi1abi

我们在这里强调取模xmody的定义:

xmody=xxy×y

其中 n表示小于等于 nn 的最大整数。

xmod2>0,就是在说x是奇数。

与此同时,经验告诉我们一个长度为 n 的序列,子序列个数有 O(2n))个,所以我们通过对答案取模来避免输出过大。

B 君觉得 G 君说的十分有道理,于是再次强调了这些基本概念。

最后,G 君听说这个题是作为 gift 送给大家,她有一句忠告。

“Vorsicht, Gift!”

“小心……剧毒!”

输入格式

第一行一个整数nn。

接下来nn行,每行一个整数,这nn行中的第ii行,表示aiai。
输出格式

一行一个整数表示答案。

input

4
15
7
3
1

output

11

限制与约定

对于前 10%10% 的测试点,n≤9,1≤ai≤13n≤9,1≤ai≤13;对于前 20%20% 的测试点,n≤17,1≤ai≤20n≤17,1≤ai≤20;对于前 40%40% 的测试点,n≤1911,1≤ai≤4000n≤1911,1≤ai≤4000;对于前 70%70% 的测试点,n≤2017n≤2017;对于前 85%85% 的测试点,n≤100084n≤100084;对于 100%100% 的测试点, 1≤n≤211985,1≤ai≤2333331≤n≤211985,1≤ai≤233333。所有的aiai互不相同,也就是说不存在i,ji,j同时满足1≤i<j≤n1≤i<j≤n和ai=ajai=aj。

时间限制:2s

空间限制:512MB


没有看过HNOIDay2T3之前咱绝对连看都看不懂标程在干嘛……
现在……到自己做的时候还是想不到……


思路:
这题不是要保证组合数的积为奇数嘛?
那么想想我们的扩展Lucas定理如何?
在扩展Lucas定理中,有一个求阶乘的快速计算部分,对吧?
配合那里使用的是不是有一个循环节分解并乘上差值的若干次方?
(就是那个对n进行cnt++,m和n-m进行cnt–的东西)
根据原理,在那一步咱会把所有的相同因子提出来用快速幂单独计算~
那么,如果我们要提的是2呢?
好了关于扩展Lucas剩下的咱就不说了~

然后是如何保证这点~
所以还是建议去看一下抛硬币的说~
首先,必须比之前的大~
其次,模2不能出事~也就是说,我们要保证上面的那个2的cnt为0~
然后仔细一想,在2的意义下那个cnt不就是在数二进制中1的个数吗……
然后,咱对每个数枚举大于它的,在它对应二进制位上都有1的所有数,加上其方案并累加入答案即可!

#include<cstdio>long long n,a,x,i,f[233334],m=1e9+7;int main(){    scanf("%lld",&n);    while(n--)    {        scanf("%lld",&x);        for(i=x;i<233334;i=i+1|x)            f[x]+=f[i];        (a+=f[x]++)%=m;        f[x]%=m;    }    printf("%lld\n",a);    return 0;}
原创粉丝点击