通过与非运算可以组合出and和not,然后and和not可以组合所有的逻辑运算。
所以只要有可能,没有表示不出来的数。但是如果所有数都满足st[i]=st[j] 那么这两位无论如何都相等。
并查集维护所有相等的类别,数位dp
还是不太熟练。
01数位dp的本质是枚举所有的非0位,假设它是0,更新答案,然后把它设为1,求之后的答案。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define inf 1e9
#define eps 1e-10
#define md
#define N 100010
using namespace std;
int mark[N],fa[N];
ll a[N];
bool vis[N];
int K;
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
int getnum(int x)
{
memset(vis,0,sizeof(vis));
for (int i=x;i>=0;i--) vis[find(i)]=1;
//for (int i=0;i<=x;i++) printf("%d %d ",fa[i],vis[i]);
int ans=0;
for (int i=0;i<=x;i++) ans+=vis[i];
return ans;
}
ll dp(ll x)
{
if (x<0) return 0;
memset(mark,-1,sizeof(mark));
ll ans=0; int t=getnum(K-1); //printf("t %d\n",t);
if ((x>>K)) return 1ll<<t;
for (int k=K-1;k>=0;k--)
{
int f=find(k);
if ((x>>k)&1)
{
if (mark[f]==1) continue;
if (mark[f]==-1)
{
mark[f]=1; t--;
ans+=(1ll<<t);
}
else if (mark[f]==0)
{
ans+=(1ll<<t);
return ans;
}
if ((!k)&&mark[f]==1) ans++;
}
else
{
if (mark[f]==-1)
{
mark[f]=0; t--;
}
else if (mark[f]==1) return ans;
if ((!k)&&mark[f]==0) ans++;
}
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.in","r",stdin); //freopen("data.out","w",stdout);
#endif
int n; ll l,r;
scanf("%d%d%lld%lld",&n,&K,&l,&r);
for (int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for (int i=0;i<K;i++) fa[i]=i;
for (int i=0;i<K;i++)
for (int j=i+1;j<K;j++)
{
bool bo=1;
for (int k=1;k<=n;k++)
if (((a[k]>>i)&1)!=((a[k]>>j)&1))
{
bo=0;
break;
}
if (bo)
{
int f1=find(i),f2=find(j);
if (f1!=f2) fa[f1]=f2;
}
}
//printf("%lld %lld\n",dp(r),dp(l-1));
printf("%lld\n",dp(r)-dp(l-1));
return 0;
}