题意,求:
\[\sum_{i=0}^{X}\sum_{j=[i=0]}^{Y}[i\&j=0]\lfloor\log_2(i+j)+1\rfloor \]为简洁,记 \(\lg(x)=\lfloor\log_2(x)\rfloor,n=\max(X,Y)\)
由于 \(i\&j=0\) 则 \(i+j=i\operatorname{|}j\) 则 \(\lg(i+j)=\lg(i\operatorname{|}j)=\lg(\max(i,j))\)。
考虑枚举 \(\lg(\max(i,j))\):
\[\sum_{k=0}^{\lg(n)} (k+1)\sum_{i=0}^{X}\sum_{j=0}^{Y}[i\&j=0][\lg(\max(i,j))=k] \]考虑枚举 \(k\),后面那一坨相当于计数。
考虑 \([i\&j=0]\) 的意义是 \(i\) 与 \(j\) 每一二进制位上不能同时为 \(1\)。
考虑 \([\lg(\max(i,j))=k]\) 的意义是 \(i\) 与 \(j\) 的第 \(k\) 二进制位上必须有且仅有一个数为 \(1\) 且第 \(k\) 位以上全为 \(0\)。
这个东西就可以数位 DP 统计,记 \(f_{pos,0/1,0/1}\) 为考虑第 \(pos\) 位时,\(i,j\) 是否被限制(这个“被限制”类比数位 DP)时的方案数。
状态数 \(O(\log n)\) 级别,转移 \(O(1)\) 级别,时间复杂度 \(O(T\log n)\)。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int MOD=1e9+7;
int T,X,Y;long long f[50][2][2],ANS;
int dfs(int pos,bool a,bool b)//a,b 表示第一个数和第二个数是否被限制
{
if(pos<0) return 1;
if(f[pos][a][b]!=-1) return f[pos][a][b];
long long ans=0;
for(int x=0;x<=(a?((X>>pos)&1):1);++x)
for(int y=0;y<=(b?((Y>>pos)&1):1);++y)
{
if(x&&y) continue;//不能同时为 1
ans+=dfs(pos-1,a&(x==((X>>pos)&1)),b&(y==((Y>>pos)&1)));
}
return f[pos][a][b]=ans%MOD;
}
int main()
{
#ifdef ONLINE_JUDGE
cin.tie(0),cout.tie(0);
ios::sync_with_stdio(0);
#endif
cin>>T;
while(T--)
{
cin>>X>>Y;ANS=0;
memset(f,-1,sizeof(f));
for(int i=0;i<=30;++i)//枚举上文中的 k
{
long long ans=0;
if((1<<i)<=X) ans+=dfs(i-1,(X-(1<<i))<(1<<i),Y<(1<<i));//使第一个数第 k 位为 1
if((1<<i)<=Y) ans+=dfs(i-1,X<(1<<i),(Y-(1<<i))<(1<<i));//使第二个数第 k 位为 1
ANS+=ans*(i+1)%MOD;
}
cout<<ANS%MOD<<'\n';
}
}
标签:lg,ICPC2020,int,max,Sum,Shanghai,pos,include,sum
From: https://www.cnblogs.com/int-R/p/P9821.html