给定一个长 的序列 ,定义一个区间 是好的,当且仅当存在某个 使得 。求将 划分为若干个好的区间的方案数,对 取模。
,。
考虑一个好的区间 以及某个 的 ,设 ,观察其需要满足的性质:
- 和 的 lowbit 相同;
- 和 除了 lowbit 外没有位同时为 ;
- 的 连续( 为按位或);
不难发现这是充要的,并且知道 higbit 最高的那个数就可以反推出另一个数。例如若已知 并且它的 higbit 最高,则 必须为 。下面不妨假定 的 higbit 比 的高。
那么考虑 cdq 分治,强制钦定某一边的 higbit 是最高的。注意到这样一定能找出所有区间,并且由于每个 唯一对应一个 ,且某一边的和一定是互不相同的,所以这样也顺带证明了总区间个数是 。
具体的,不妨钦定右侧的 higbit 最高,那么从 往 枚举,暴力进位并配合异或哈希求出每一个 ;再从 往 枚举,暴力进位的同时维护 higbit 和 lowbit,这样就可以求出当前需要的 ,用哈希表找到这个 对应的左端点即可。
另一种情况同理。由于每次最多会让总进位次数 ,所以时间复杂度是正确的。
找到所有区间后直接跑 dp 即可。注意需要开一个 vis 数组来去重。
时间复杂度 ,代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
#include <ctime>
#include <random>
using namespace std;
template<typename T>
inline void read(T &x)
{
x=0;
T w=1;
char c=getchar();
while(c<'0'||c>'9') w=(c=='-'?-w:w),c=getchar();
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
x*=w;
}
typedef unsigned long long ull;
const int S=300005,MS=2000005;
#define p 1000000007
int n,a[S];
vector<int> lb[S];
mt19937_64 rnd(time(NULL));
ull val[MS],pre[MS];
bool vis[S];
int f[S];
namespace pot
{
int hb,lb,b[MS];
ull hs;
vector<int> tmp;
inline void init()
{
hb=-1,lb=MS;
hs=0;
for(int x:tmp) b[x]=0;
tmp.clear();
}
inline void ins(int x)
{
b[x]++,hs^=val[x];
tmp.push_back(x);
lb=min(lb,x),hb=max(hb,x);
while(b[x]==2)
{
b[x]=0,b[x+1]++,hs^=val[x+1];
tmp.push_back(x+1);
if(x==lb) lb++;
hb=max(hb,x+1);
x++;
}
}
inline ull que()
{
return pre[hb]^pre[lb]^hs;
}
}
namespace hsh
{
const int pp=1145143;
vector<pair<ull,int> > vec[pp];
vector<int> tmp;
inline void init()
{
for(int x:tmp) vec[x].clear();
tmp.clear();
}
inline void ins(ull x,int y)
{
int id=x%pp;
vec[id].emplace_back(x,y);
tmp.push_back(id);
}
inline int que(ull x)
{
int id=x%pp;
for(auto t:vec[id]) if(t.first==x) return t.second;
return -1;
}
}
inline void work(int l,int r)
{
if(l==r) return lb[r].push_back(l),void();
int mid=l+r>>1;
work(l,mid),work(mid+1,r);
pot::init(),hsh::init();
for(int i=mid;i>=l;i--)
{
pot::ins(a[i]);
hsh::ins(pot::hs,i);
}
pot::init();
for(int i=mid+1;i<=r;i++)
{
pot::ins(a[i]);
int x=hsh::que(pot::que());
if(x!=-1) lb[i].push_back(x);
}
pot::init(),hsh::init();
for(int i=mid+1;i<=r;i++)
{
pot::ins(a[i]);
hsh::ins(pot::hs,i);
}
pot::init();
for(int i=mid;i>=l;i--)
{
pot::ins(a[i]);
int x=hsh::que(pot::que());
if(x!=-1) lb[x].push_back(i);
}
}
inline void add(int &x,int y)
{
x+=y;
if(x>=p) x-=p;
}
int main()
{
for(int i=0;i<=MS-3;i++) val[i]=rnd();
for(int i=1;i<=MS-3;i++) pre[i]=pre[i-1]^val[i];
read(n);
for(int i=1;i<=n;i++) read(a[i]);
work(1,n);
f[0]=1;
for(int i=1;i<=n;i++)
{
for(int x:lb[i])
{
if(vis[x]) continue;
vis[x]=true;
add(f[i],f[x-1]);
}
for(int x:lb[i]) vis[x]=false;
}
printf("%d\n",f[n]);
return 0;
}