2019牛客暑期多校训练营(第七场)Pair (数位dp)

链接:https://ac.nowcoder.com/acm/contest/887/H
来源:牛客网
 

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

Given three integers  Count the number of pairs <x, y> (with 1≤x≤A1)
such that at least one of the following is true:

("and", "xor" are bit operators)

输入描述:

The first line of the input gives the number of test cases, T (T≤100)T\ (T \leq 100)T (T≤100).  test cases follow.

For each test case, the only line contains three integers ,  and .
1≤A,B,C≤1091 \leq A,B,C \leq 10^91≤A,B,C≤109

输出描述:

For each test case, the only line contains an integer that is the number of pairs satisfying the condition given in the problem statement.

示例1

输入

复制

3
3 4 2
4 5 2
7 8 5

输出

复制

5
7
31

给定A, B, C,

需要求有多少个pair 满足 • x & y > C or x ^ y < C •

直接数位DP一下求解

当然以上是邝斌说的

------------------------------------------------------

这题不妨设d[i][alim][blim][sta1][sta2];

表示数位上第i位,a, b 分别被限制的状态, 以及 and 操作, xor操作目前的状态

0 表示已经不满足, 1 表示 正在比较可能满足 ,3表示已经满足了

显然对于每一位

1 如果之前已经不满足, 该位无论怎么样都不满足了

2 如果之前可能满足, 该位不满足, 则不满足, 若该位满足, 则满足

3 如果之前已经满足, 该位无论怎么样都满足

最后位数为0时, 只要sta1, sta2 有一个为2, 即满足。

因为数位dp时会算上x = 0, y = 0,C = 0 的情况, 所以最后要减去零的情况。 

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

#ifdef LOCAL
#define debug(x) cout << "[" __FUNCTION__ ": " #x " = " << (x) << "]\n"
#define TIME cout << "RuningTime: " << clock() << "ms\n", 0
#else
#define TIME 0
#endif
#define continue(x) { x; continue; }
#define break(x) { x; break; }
const int N = 5e4 + 10;
int mod = 998244353;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
ll d[40][2][2][3][3]; // 0不满足 1可能满足 2 已经满足
int a[40];
int b[40];
int c[40];
ll dfs(int pos, int alim, int blim, int u, int v) // u == &    v == ^
{
	if (pos == 0)
		return u == 2 || v == 2;
	if (d[pos][alim][blim][u][v] != -1)
		return d[pos][alim][blim][u][v];
	int up1 = alim ? a[pos] : 1;
	int up2 = blim ? b[pos] : 1;
	ll sum = 0;
	for (int i = 0; i <= up1; i++)
		for (int j = 0; j <= up2; j++)
		{
			int nowu = u, nowv = v;
			if ((i & j) > c[pos] && u)
				nowu = 2;
			if ((i & j) < c[pos] && u != 2)
				nowu = 0;
			if ((i ^ j) < c[pos] && v)
				nowv = 2;
			if ((i ^ j) > c[pos] && v != 2)
				nowv = 0;
			if (!nowu && !nowv)
				continue;
			sum += dfs(pos - 1, alim && i == up1, blim && j == up2, nowu, nowv);
		}
	return d[pos][alim][blim][u][v] = sum;
}
ll get_num(int x, int y, int z)
{
	int cnt = 0;
	memset(d, -1, sizeof d);
	memset(a, 0, sizeof a);
	memset(b, 0, sizeof b);
	memset(c, 0, sizeof c);
	int cnt1 = 0;
	while (x)
		a[++cnt1] = x % 2, x /= 2;
	int cnt2 = 0;
	while (y)
		b[++cnt2] = y % 2, y /= 2;
	int cnt3 = 0;
	while (z)
		c[++cnt3] = z % 2, z /= 2;
	int M = max({ cnt1, cnt2, cnt3 });
	return dfs(M, 1, 1, 1, 1);
}
int main(){
#ifdef LOCAL
	freopen("D:/input.txt", "r", stdin);
#endif
	int t;
	cin >> t;
	while (t--)
	{
		int A, B, C;
		cin >> A >> B >> C;
		ll zero = min(A, C - 1) + min(B, C - 1) + 1;
		cout << get_num(A, B, C) - zero << endl;
	}
	return TIME;
}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值