[CTSC2017]吉夫特
作者:互联网
吉夫特
题解
挺水的一道题。
既然题面已经明示了这一串组合数相乘必须为奇数,我们考虑如何判断一个组合数为奇数。
因为
C
x
y
≡
1
(
m
o
d
2
)
C_{x}^{y}\equiv 1\,(mod\,2)
Cxy≡1(mod2),根据卢卡斯定理有,
设
b
i
t
x
,
i
bit_{x,i}
bitx,i表示
x
x
x第
i
i
i位二进制的值,则
∏
C
b
i
t
x
,
i
b
i
t
y
,
i
=
1
\prod C_{bit_{x,i}}^{bit_{y,i}}=1
∏Cbitx,ibity,i=1。
很明显,只有当
y
y
y的二进制集合是
x
x
x的二进制集合的子集时上面的条件才成立。
所以,我们的
b
b
b序列必须满足
a
b
i
o
r
a
b
i
−
1
=
a
b
i
−
1
a_{b_{i}} or\, a_{b_{i-1}}=a_{b_{i-1}}
abiorabi−1=abi−1。
看到上式我们很快就想到了
d
p
dp
dp,令
d
p
i
dp_{i}
dpi为以
a
i
a_{i}
ai结尾的序列的方案数,然后枚举子集转移。
但我们很快发现,直接暴力做是
O
(
n
2
)
O(n^2)
O(n2)的,会T飞。
考虑折半,
f
x
,
y
f_{x,y}
fx,y表示前9位为
x
x
x,后九位是
y
y
y的超集的
d
p
dp
dp值之和。
每加入一个数时我们就先算出它的
d
p
dp
dp值,再加到
f
f
f上。
时间复杂度 6 n 2 6^{\frac{n}{2}} 62n。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 300005
#define MAXM 525
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const int lim=(1<<9);
const int mo=1e9+7;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
int n,a[MAXN],f[MAXM][MAXM],ans;
inline int add(const int x,const int y){return x+y<mo?x+y:x+y-mo;}
signed main(){
read(n);
for(reg int i=1;i<=n;++i){
read(a[i]);const int u=a[i]>>9,v=a[i]&(lim-1);int tmp=add(1,f[u][v]);
for(reg int i=u^(lim-1);i;i=(i-1)&((lim-1)^u))tmp=add(tmp,f[i|u][v]);
for(reg int i=v;i;i=(i-1)&v)f[u][i]=add(f[u][i],tmp);f[u][0]=add(f[u][0],tmp);
}
for(reg int i=0;i<lim;++i)ans=add(ans,f[i][0]);
printf("%d\n",add(ans,mo-n));
return 0;
}
谢谢!!!
标签:tmp,int,long,reg,add,夫特,CTSC2017,dp 来源: https://blog.csdn.net/Tan_tan_tann/article/details/113818328