吉夫特
简单的题目,既是礼物,也是毒药。
B 君设计了一道简单的题目,准备作为 gift 送给大家。
输入一个长度为
n
的数列
问有多少个长度大于等于
2
的不上升的子序列
∏ki=2(abi−1abi)mod2=(ab1ab2)×(ab2ab3)×⋯×(abk−1abk)mod2>0
输出这个个数对 1000000007 取模的结果。
G 君看到题目后,为大家解释了一些基本概念。
我们选择任意多个整数 bibi 满足
1≤b1<b2<⋯<bk−1<bk≤n
我们称 ab1,ab2,…,abk 是 aa 的一个子序列。
如果这个子序列同时还满足
ab1≥ab2≥⋯≥abk−1≥abk
我们称这个子序列是不上升的。
组合数
(nm)
是从
n
个互不相同的元素中取
(nm)=n!m!(n−m)!=n×(n−1)×⋯×2×1(m×(m−1)×⋯×2×1)((n−m)×(n−m−1)×⋯×2×1)
这里要特别注意,因为我们只考虑不上升子序列,所以在求组合数的过程中,一定满足 n≥mn≥m,也就是 (abi−1abi) 中一定有 abi−1≥abi 。
我们在这里强调取模 xmody 的定义:
xmody=x−⌊xy⌋×y
其中 ⌊n⌋ 表示小于等于 nn 的最大整数。
xmod2>0 ,就是在说 x 是奇数。
与此同时,经验告诉我们一个长度为
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;
}