【2022noip多校】异或
【题目描述】
对于一个元素介于 且互不相同的长度为 的序列 ,定义它的特征序列为 ,其中 表示使得 与 的异或值最大的下标。
形式化地,定义
给定一个特征序列 ,求有多少个满足要求的原序列 可以得到这个特征序列。
答案对 取模
【样例】
【样例输入1】
6 3
1 1 2 2 3 4 5 6
【样例输出1】
4
【解析】
首先明确,合法的 中,必定出现完整的
将 的二进制形式依次写出(取 )
000 001 010 011 100 101 110 111
发现每次取一半,在第 次时,会使从高到底第 为发生 分割
所以考虑分治:
设状态 表示在 中,任意 的前 位相同, 表示分治深度。
其实这也代表了 前 位相同,这个可以从之前的例子中看出。
接下来考虑下一层:
-
若集合 则表示下一位这两边也相同,则将方案数乘二,问题规模减半
-
若集合 则代表下一位不同,且可以得出 的 位一定为 , 的 位一定为 ,因为要保持最大且左区间的 位均为 ,右区间均为 所以有以上结论。之后这两种情况就独立了,乘法原理直接乘起来就可以了。
考虑无解,即集合 但 就无解。
【CODE】
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn = (1<<16)+33;
inline ll read_int(){
ll a=0;bool f=0;char g=getchar();
while(g<'0'||'9'<g) {if(g=='-') f=1;g=getchar();}
while('0'<=g&&g<='9') a=a*10+g-'0',g=getchar();
return f ? -a : a;
}
inline void write(ll a,bool b=1){
if(a<0) a=-a,putchar('-');
ll lin[30],top=0;
while(a) lin[++top]=a%10,a/=10;
if(top==0) lin[++top]=0;
while(top) putchar(lin[top--]+'0');
if(b) putchar('\n');
}
ll n,m,mod=1e9+7;
ll sj[maxn];
ll vis[maxn];
inline ll fz(ll l,ll r){
// cout<<l<<" "<<r<<endl;
if(l==r) return 1;
ll mid=(l+r)>>1;
int bt=0,xd=0;
set<int> a,b;
int f=0;
for(int i=l;i<=mid;i++) a.emplace(sj[i]);
for(int i=mid+1;i<=r;i++) b.emplace(sj[i]),f= (f||(a.find(sj[i])!=a.end()) ? 1 : 0);
if(f&&a!=b) return 0;
if(a==b) return (ll)2*fz(l,mid)%mod;
else return fz(l,mid)*fz(mid+1,r)%mod;
}
inline void read(){
n=read_int(),m=read_int();
for(int i=1;i<=(1<<m);i++) sj[i]=read_int(),vis[sj[i]]=1;
for(int i=1;i<=n;i++){
if(vis[i]==0) {write(0);return;}
}
write(fz(1,(1<<m)));
}
int main (){
// freopen(".out","w",stdout);
read();
// while(1) getchar();
}
【后记】
如有大佬知道之前那个合法的 中必有 是如何证明的,请留言
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效