既然选择了远方,便只顾风雨兼行|

H_W_Y

园龄:1年10个月粉丝:28关注:15

2023-04-22 10:25阅读: 107评论: 0推荐: 0

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

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

题目描述

分析

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

由2可知:ab=c
a+b>ab
这样就得到了需要满足的三个条件:
1.ac
2.bc
3.ab<a+b而这种情况只有a=1b=1的情况出现后才满足
而对于任意一位,满足条件的只有四组(a,b,c)
(1,1,0),(0,0,0),(1,0,1),(0,1,0)
我们就可以只对c进行限制将三种状态状压来进行数位dp
可以令flag<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.多种状态可以采用状压来存储

本文作者:H_W_Y

本文链接:https://www.cnblogs.com/H-W-Y/p/17342556.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   H_W_Y  阅读(107)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起