P9821 [ICPC2020 Shanghai R] Sum of Log

发布时间 2023-11-05 18:43:54作者: int_R

原题链接

题意,求:

\[\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';
    }
}