1 条题解
-
0
自动搬运
来自洛谷,原作者为

Salamander
**搬运于
2025-08-24 21:46:38,当前版本为作者最后更新于2018-02-02 10:54:44,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
与非()是非常强大的位运算,可以表示出其他所有的位运算:
所以相当于是这个数之间可以做任何位运算。
然后我们考虑一下位与位之间的限制。如果这个数中每个数的第位和第位都相同,那么这个数无论怎么运算,最后得到的答案中第位和第位一定相同。我们在数位dp的时候从高位到低位考虑,确定了当前位后把必须和它相同的位也标记一下,就可以求出中能运算出的数的个数。
为什么这样是对的?其他没有互相限制的位置上就一定可以任意取或了吗?
类似于线性基的思想,我们可以构造这样一种方案:通过一些运算把某一位上只留下一个,其他的数在这一位上都为,最后用它们或起来就可以构造出任意一个数。对于第位,假设没有限制,那么我们把这一位上为的数全都取反,然后全部与起来,得到的数这一位上肯定是;同时由于这一位没有限制,所以不会有其他位置上再出现一个,因为如果还出现就表每一个数中那一位与第位都相等,于是就产生了限制,矛盾。所以对于没有限制的位,我们一定可以构造出一个只有这一位上为的数。对于几个必须相等的位,这样可以构造出一个只有这几位为的数。
于是我们可以把个数构造出一个类似这样的东西,假设最左边第位,那么下面这个东西中间的限制就是第位和第位必须相等,第位和第位必须相等。
10000000 01000000 00101000 00010000 00000100 00000011利用这样的东西,我们通过他们之间的或运算,就可以构造出原来个数所能构造出的所有数,所以数位dp就可以直接做了。首先暴力求出哪些位必须相等。
复杂度应该是。
#include<vector> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define For(i,_beg,_end) for(int i=(_beg),i##end=(_end);i<=i##end;++i) #define Rep(i,_beg,_end) for(int i=(_beg),i##end=(_end);i>=i##end;--i) template<typename T>T Max(const T &x,const T &y){return x<y?y:x;} template<typename T>T Min(const T &x,const T &y){return x<y?x:y;} template<typename T>int chkmax(T &x,const T &y){return x<y?(x=y,1):0;} template<typename T>int chkmin(T &x,const T &y){return x>y?(x=y,1):0;} template<typename T>void read(T &x){ T f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(x=0;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0'; x*=f; } typedef long long LL; const int maxn=1010; int n,k,c[65],tmp[65]; LL a[maxn],L,R; vector<int>pos[65]; LL Dfs(LL n,int x,bool lim){ if(x<0)return 1; if(!lim){ int cnt=0; memcpy(tmp,c,sizeof c); Rep(i,x,0) if(tmp[i]==-1){ cnt++; For(j,0,pos[i].size()-1) tmp[pos[i][j]]=1; } return 1LL<<cnt; } LL res=0; if(c[x]==-1){ For(i,0,(n>>x)&1){ For(j,0,pos[x].size()-1) c[pos[x][j]]=i; res+=Dfs(n,x-1,lim&(i==((n>>x)&1))); } For(j,0,pos[x].size()-1) c[pos[x][j]]=-1; return res; } else{ if(c[x]&&lim&&!((n>>x)&1))return 0; return Dfs(n,x-1,lim&(c[x]==((n>>x)&1))); } } LL Solve(LL x){ memset(c,-1,sizeof c); if(x<0)return 0; return Dfs(x,k-1,(x>>k)?0:1); } int main(){ read(n);read(k);read(L);read(R); For(i,1,n) read(a[i]); Rep(i,k-1,1) Rep(j,i-1,0){ bool flag=true; For(p,1,n) if(((a[p]>>i)&1)^((a[p]>>j)&1)){ flag=false; break; } if(flag) pos[i].push_back(j); } printf("%lld\n",Solve(R)-Solve(L-1)); return 0; }
- 1
信息
- ID
- 2293
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者