习题:Daniel and Spring Cleaning(数位DP)

题目

传送门

思路

比较有意思的转换

考虑如果要满足\(a+b=a\oplus b\)

那么定然a和b的每一位一定满足\(a\&b==1\)

之后按数位DP的套路来做即可

考虑对式子进行一个容斥

\(\sum_{a=l}^r\sum_{b=l}^{r}[a+b=a\oplus b]=\sum_{a=0}^{r}\sum_{b=0}^{r}[a+b=a\oplus b]-2*\sum_{a=0}^{l-1}\sum_{b=0}^{r}[a+b=a\oplus b]+\sum_{a=0}^{l-1}\sum_{b=0}^{l-1}[a+b=a\oplus b]\)

这样就可以排除下界的影响

代码

#include
#include
using namespace std;
int t;
int l,r;
int limitx[100],limity[100];
int lenx,leny;
long long dp[100][2][2];
void divide(long long val,int *limit,int &len)
{
    len=0;
    while(val)
    {
        limit[len++]=(val&1);
        val>>=1;
    }
    len--;
}
long long solve(long long pos,int limx,int limy)
{
    if(pos==-1)
        return 1;
    if(dp[pos][limx][limy]!=-1)
        return dp[pos][limx][limy];
    dp[pos][limx][limy]=0;
    for(int i=0;i<=(limx?limitx[pos]:1);i++)
        for(int j=0;j<=(limy?limity[pos]:1);j++)
            if(!(i&j))
                dp[pos][limx][limy]+=solve(pos-1,limx&&i==limitx[pos],limy&&j==limity[pos]);
    return dp[pos][limx][limy];
}
long long calc(long long x,long long y)
{
    memset(dp,-1,sizeof(dp));
    memset(limitx,0,sizeof(limitx));
    memset(limity,0,sizeof(limity));
    if(y==-1||x==-1)
    	return 0;
    divide(x,limitx,lenx);
    divide(y,limity,leny);
    return solve(max(lenx,leny),1,1);
}
int main()
{
    cin>>t;  
    for(int i=1;i<=t;i++)
    {
        cin>>l>>r;
        cout<

你可能感兴趣的:(习题:Daniel and Spring Cleaning(数位DP))