标签:原理 names class typedef string temp 传送门 部分 scan
给你两个数,\(l,r\) 求 \([l,r]\) 中多少对 \(a+b=a\oplus b\)。
看了大佬的题解才知道这里要用到二维容斥。
设 \(f_{x,y}\) 是 \(a\in [0,x],b\in [0,y]\) 时满足条件的对数
那么根据容斥原理答案就是 \(f_{r,r}-f_{l-1,r}\times 2+f_{l-1,l-1}\)
对于其中每一部分都可以用一次数位DP求出来
因为这里对于统计有影响的因素只有两个数是否被限制
那么状态可以直接设计为 \(dp_{pos,lim1,lim2}\)
代表在 \(pos\) 位 \(a,b\) 是否被限制时的个数。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
typedef long long LL;
int T,a[70],b[70];
LL f[70][2][2];
LL dfs(int pos,int lim1,int lim2){
if(pos==-1) return 1;
if(f[pos][lim1][lim2]!=-1) return f[pos][lim1][lim2];
LL temp=0;
int up1=lim1?a[pos]:1,up2=lim2?b[pos]:1;
for(int i=0;i<=up1;i++)
for(int j=0;j<=up2;j++){
if(i==1&&j==1) continue;
temp+=dfs(pos-1,lim1&&i==a[pos],lim2&&j==b[pos]);
}
f[pos][lim1][lim2]=temp;
return temp;
}
LL solve(int x,int y){
memset(f,-1,sizeof(f));
int pos;
for(pos=0;x||y;pos++,x/=2,y/=2)
a[pos]=x%2,b[pos]=y%2;
return dfs(pos-1,1,1);
}
int main(){
scanf("%d",&T);
int l,r;
memset(f,-1,sizeof(f));
while(T--){
scanf("%d%d",&l,&r);
printf("%lld\n",solve(r,r)-2*solve(l-1,r)+solve(l-1,l-1));
}
return 0;
}
Codeforces 1245F. Daniel and Spring Cleaning(容斥原理+数位DP)
标签:原理 names class typedef string temp 传送门 部分 scan
原文地址:https://www.cnblogs.com/BakaCirno/p/11828726.html