题目描述
简单的题目,既是礼物,也是毒药。
B 君设计了一道简单的题目,准备作为 gift 送给大家。
输入一个长度为 n 的数列 a1,a2,⋯,an 问有多少个长度大于等于 2 的不上升的子序列满足:
∏i=2k(abi−1abi) mod 2=(ab1ab2)×(ab2ab3)×⋯×(abk−1abk) mod 2>0\prod_{i = 2}^k \binom{a_{b_{i-1}}}{a_{b_i}} \bmod 2= \binom{a_{b_1}}{a_{b_2}} \times \binom{a_{b_2}}{a_{b_3}} \times \cdots \times \binom{a_{b_{k-1}}}{a_{b_k}} \bmod 2 > 0∏i=2k(abiabi−1)mod2=(ab2ab1)×(ab3ab2)×⋯×(abkabk−1)mod2>0
输出这个个数对 1000000007 取模的结果。
G 君看到题目后,为大家解释了一些基本概念。
我们选择任意多个整数 bi 满足
1≤b1<b2<⋯<bk−1<bk≤n1 \leq b_1 < b_2 < \cdots < b_{k-1} < b_{k} \leq n1≤b1<b2<⋯<bk−1<bk≤n
我们称 ab1,ab2,…,abk 是 a 的一个子序列。
如果这个子序列同时还满足ab1≥ab2≥⋯≥abk−1≥abka_{b_1} \geq a_{b_2} \geq \cdots \geq a_{b_{k-1}} \geq a_{b_{k}}ab1≥ab2≥⋯≥abk−1≥abk
我们称这个子序列是不上升的。
组合数(nm)\binom{n}{m}(mn) 是从 n 个互不相同的元素中取 m 个元素的方案数,具体计算方法如下:
(nm)=n!m!(n−m)!=n×(n−1)×⋯×2×1(m×(m−1)×⋯×2×1)((n−m)×(n−m−1)×⋯×2×1)\binom{n}{m} = \frac{n!}{m!(n-m)!} = \frac{n \times (n - 1) \times \cdots \times 2 \times 1}{(m \times (m - 1) \times \cdots \times 2 \times 1)((n-m) \times (n-m - 1) \times \cdots \times 2 \times 1)}(mn)=m!(n−m)!n!=(m×(m−1)×⋯×2×1)((n−m)×(n−m−1)×⋯×2×1)n×(n−1)×⋯×2×1
这里要特别注意,因为我们只考虑不上升子序列,所以在求组合数的过程中,一定满足n≥mn \geq mn≥m也就是(abi−1abi)\binom{a_{b_{i-1}}}{a_{b_{i}}}(abiabi−1)中一定有abi−1≥abia_{b_{i-1}} \geq a_{b_{i}}abi−1≥abi
我们在这里强调取模x mod yx \bmod yxmody的定义 x mod y=x−⌊xy⌋×yx \bmod y = x - \left \lfloor \frac{x}{y} \right \rfloor \times yxmody=x−⌊yx⌋×y 其中 ⌊n⌋⌊n⌋⌊n⌋表示小于等于 n 的最大整数。
x mod 2>0x \bmod 2 > 0xmod2>0就是在说x是奇数。
与此同时,经验告诉我们一个长度为 nn 的序列,子序列个数有O(n2)O(n^2)O(n2)个,所以我们通过对答案取模来避免输出过大。
B 君觉得 G 君说的十分有道理,于是再次强调了这些基本概念。
最后,G 君听说这个题是作为 gift 送给大家,她有一句忠告。
“Vorsicht, Gift!”
“小心……剧毒!”
输入输出格式
输入格式:
第一行一个整数 n。
接下来 n 行,每行一个整数,这 n 行中的第 i 行,表示 ai。
输出格式:
一行一个整数表示答案。
输入输出样例
输入样例#1:
4
15
7
3
1
输出样例#1:
11
说明
• 对于前 10% 的测试点, n ≤ 9, 1 ≤ ai ≤ 13;
• 对于前 20% 的测试点, n ≤ 17, 1 ≤ ai ≤ 20;
• 对于前 40% 的测试点, n ≤ 1911, 1 ≤ ai ≤ 4000;
• 对于前 70% 的测试点, n ≤ 2017;
• 对于前 85% 的测试点, n ≤ 100084;
• 对于 100% 的测试点, 1 ≤ n ≤ 211985, 1 ≤ ai ≤ 233333。所有的 ai 互不相同,也就是说不存在 i, j 同时满足 1 ≤ i < j ≤ n 和 ai = aj。
先找性质,要求满足
∏i=2k(abi−1abi) mod 2=(ab1ab2)×(ab2ab3)×⋯×(abk−1abk) mod 2>0\prod_{i = 2}^k \binom{a_{b_{i-1}}}{a_{b_i}} \bmod 2= \binom{a_{b_1}}{a_{b_2}} \times \binom{a_{b_2}}{a_{b_3}} \times \cdots \times \binom{a_{b_{k-1}}}{a_{b_k}} \bmod 2 > 0∏i=2k(abiabi−1)mod2=(ab2ab1)×(ab3ab2)×⋯×(abkabk−1)mod2>0
如果(abi−1abi) mod 2=1\binom{a_{b_{i-1}}}{a_{b_i}}\bmod 2=1(abiabi−1)mod2=1,那么我们根据Lucas定理,由于(10)=1,(11)=1,(00)=1,(01)=0\binom{1}{0}=1,\binom{1}{1}=1,\binom{0}{0}=1,\binom{0}{1}=0(01)=1,(11)=1,(00)=1,(10)=0,所以不存在(01)\binom{0}{1}(10),那也就是说abi-1&abi=abi-1,也就是说右边的数在左边的数的子集里。
于是就有了做法,子集DP,这道题就是子集DP。这道题就是简单的枚举子集,我们知道枚举子集的复杂度为3n3^n3n。我们对于每个aia_iai,枚举它的子集,然后如果子集中有在序列中位于其右边的数,那么就将答案统计上去。复杂度我也不是特别会证,反正复杂度就是O(跑得过)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
char c;int x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
const int MD=1e9+7;
int n,a[220000],p[240000];
ll ans,sum[240000];
int calc(int x){
if(sum[x]) return sum[x];
int res=0;sum[x]=1;
for(int i=x;i;i=(i-1)&x){
if(i==x||!p[i]) continue;
if(p[i]>p[x]) (res+=calc(i))%=MD;
}
(sum[x]+=res)%=MD;
return sum[x];
}
int main()
{
n=read();
for(int i=1;i<=n;i++) a[i]=read(),p[a[i]]=i;
for(int i=1;i<=n;i++) (ans+=calc(a[i]))%=MD;
printf("%lld",(ans-n+MD)%MD);
return 0;
}