[P8766 [蓝桥杯 2021 国 AB] 异或三角]题解-数位DP

P8766 [蓝桥杯 2021 国 AB] 异或三角

题目描述

分析

题目中给出了三个限制
首先我们不妨设\(a,b \lt c\),则
而由于我们把\(c\)作为了最大值,原题需要有序对\((a,b,c)\)
所以\(ans \ast 3\)
1.\(1 \leq a,b,c \leq n\)
2.\(a \oplus b \oplus c=0\)
3.\(a+b \gt c\)
而在枚举过程中,我们只需要保证\(c \lt n\)即可

由2可知:\(a \oplus b=c\)
\(a+b \gt a \oplus b\)
这样就得到了需要满足的三个条件:
1.\(a\le c\)
2.\(b\le c\)
3.\(a \oplus b \lt a+b\)而这种情况只有\(a=1\)\(b=1\)的情况出现后才满足
而对于任意一位,满足条件的只有四组\((a,b,c)\)
\((1,1,0),(0,0,0),(1,0,1),(0,1,0)\)
我们就可以只对\(c\)进行限制将三种状态状压来进行数位dp
可以令\(flag \lt 8\)
它的每一位分别表示我们所要的限制即可

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long

int n,T,a[50],len=0;
ll dp[50][10][2];

//当前枚举到第id位,是否满足三个状态flag,c是否达到上限limit
ll dfs(int id,int flag,int limit){
  //1.出口
  if(id==0) return flag==7;//满足所有条件
  if(dp[id][flag][limit]!=-1) return dp[id][flag][limit]; 
  //2.能做的事情 
  int bound= limit==1 ?a[id]:1;
  ll res=0;
  for(int i=0;i<=bound;i++){
  	if(i==0){//c=0 对应 (0,0,0),(1,1,0) 
  	  int a=flag&1,b=flag>>1 &1;//判断a<c,b<c
	  res+=dfs(id-1,flag,limit&&i==bound);//(a,b,c)=(0,0,0)
	  if(a&&b) res+=dfs(id-1,flag|4,limit&&i==bound); //(a,b,c)=(1,1,0)
	}
	if(i==1){//c=0 对应 (1,0,1),(0,1,1) 
	  res+=dfs(id-1,flag|2,limit&&i==bound);//(a,b,c)=(1,0,1)满足b<c 
	  res+=dfs(id-1,flag|1,limit&&i==bound);//(a,b,c)=(0,1,1)满足a<c 
	}
  }
  return dp[id][flag][limit]=res;
} 

ll solve(int x){
  len=0;
  while(x){
  	a[++len]=x%2;
  	x/=2;
  }
  memset(dp,-1,sizeof(dp));
  return dfs(len,0,1);
}

int main(){
  /*2023.4.22 hewanying P8766 [蓝桥杯 2021 国 AB] 异或三角 数位dp*/ 
  scanf("%d",&T);
  while(T--){
    scanf("%d",&n);
    printf("%lld\n",solve(n)*3);
  }
  return 0;
}

总结

1.在我们特定顺序时,一定要注意题目给的是有序对还是无序对,要进行相应的转换
2.定了\(a,b,c\)的大小关系时,只需要判断最大的小于limit即可
3.多种状态可以采用状压来存储

posted @ 2023-04-22 10:25  H_W_Y  阅读(143)  评论(0)    收藏  举报