D&D 题解
Otomachi_Una_ · · 题解
隐藏的视频
标题
简单喵喵题
本题是一道结论题,本题只介绍
划分完以后每一个集合的装饰子集与原数列的装饰子集相同。
一个直观的证明方法就是把每个数化为二进制。下面讲一讲严谨的证明。
我们设原数组的装饰子集为
结论 1:假设
x\in F 则x 在划分后的装饰子集中出现。
这个结论是显然的,反证法即可。
结论 2:假设
x\not \in F 则x 不在划分后的装饰子集当中出现。
反之,必然有一个
结论 3:对于原数组的子集
B ,只要F\subseteq B 那么B 的可爱子集是F 。
这个结论也是显然的。
有了结论,我们现在进一步解决该问题。
- 快速求出原数组的装饰子集
考虑把
void dfs(int x){
if(flag[x]) return;
flag[x]=true;
for(int i=0;i<=20;i++)
if(x&(1<<i))
dfs(x-(1<<i));
return;
}
对于
- 快速求出划分方案
这里发现只要
用前缀和优化即可。
参考代码
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e6+5;
const int MOD=1e9+7;
int n;int a[MAXN],b[MAXN];
bool flag[MAXN];int col[MAXN];
int f[MAXN];int s[MAXN];int cnt=0,tmp=0;
int res[MAXN];
int L[MAXN];//L[i]表示最大的x使得[x,i]构成一个装饰子集.
void dfs(int x){
if(flag[x]) return;
flag[x]=true;
for(int i=0;i<=20;i++)
if(x&(1<<i))
dfs(x-(1<<i));
return;
}
void cute_sub(){
sort(b+1,b+n+1);
for(int i=n;i>=1;i--)
if(!flag[b[i]]){
col[b[i]]=++cnt;
dfs(b[i]);
}
for(int i=1;i<=n;i++)
a[i]=col[a[i]];
return;
}
void find_left(){
int l=0;
for(int i=1;i<=n;i++){
if(a[i]!=0&&res[a[i]]++==0) tmp++;
if(l==0&&tmp<cnt) L[i]=n+2;
while(tmp==cnt){
l++;
if(a[l]!=0&&--res[a[l]]==0) tmp--;
}
if(!L[i]) L[i]=l;
}
return;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i],b[i]=a[i];
cute_sub();
find_left();
s[0]=1;
for(int i=1;i<=n;i++)
s[i]=(s[i-1]+s[L[i]-1])%MOD;
cout<<(s[n]-s[n-1]+MOD)%MOD;
return 0;
}