通过与非运算可以组合出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; }