TopCoder 11379 YetAnotherORProblem / 模拟赛 T3 yet another 计数题

原题:
Problem Statement

NOTE: This problem statement contains subscripts that may not display properly if viewed outside of the applet. You’re given a long[] R containing N elements. Count the number of sequences A0, A1, …, AN-1 such that each Ai is an integer satisfying 0 &le Ai &le R[i] and A0 + A1 + … + AN-1 = A0 | A1 | … | AN-1. The ‘|’ symbol stands for bitwise OR of the operands. Return the number of such sequences modulo 1,000,000,009.

Definition

Class: YetAnotherORProblem
Method: countSequences
Parameters: long[]
Returns: int
Method signature: int countSequences(long[] R)
(be sure your method is public)

Notes
  • If a and b are single bits then a | b is defined as max(a, b). For two integers, A and B, in order to calculate A | B, they need to be represented in binary: A = (an…a1)2, B = (bn…b1)2 (if the lengths of their representations are different, the shorter one is prepended with the necessary number of leading zeroes). Then A | B = C = (cn…c1)2, where ci = ai | bi. For example, 10 | 3 = (1010)2 | (0011)2 = (1011)2 = 11.
Constraints
  • R will contain between 2 and 10 elements, inclusive.
  • Each element of R will be between 1 and 10^18, inclusive.
Examples

0)
{3,5}
Returns: 15
All the possible sequences are: {0,0}, {0,1}, {0,2}, {0,3}, {0,4}, {0,5}, {1,0}, {1,2}, {1,4}, {2,0}, {2,1}, {2,4}, {2,5}, {3,0}, {3,4}.
1)
{3,3,3}
Returns: 16
2)
{1,128}
Returns: 194
3)
{26,74,25,30}
Returns: 8409
4)
{1000000000,1000000000}
Returns: 420352509

模拟赛题(翻译):

给你一个数组R,包含N个元素,求有多少满足条件的序列AA使得

0 ≤ A [ i ] A[i] A[i] R [ i ] R[i] R[i]
A [ 0 ] A[0] A[0]+ A [ 1 ] A[1] A[1]+…+ A [ N − 1 ] A[N-1] A[N1] = A [ 0 ] A[0] A[0] | A [ 1 ] A[1] A[1]… | A [ N − 1 ] A[N-1] A[N1]
输出答案对1e9+9取模

输入

第一行输入一个整数N (102 ≤ N ≤ 10)

第二行输入N个整数 R [ i ] R[i] R[i] (1 ≤ R [ i ] R[i] R[i] ≤ 1e18)

输出

输出一个整数

样例

输入
2
3 5
输出
15
输入
3
3 3 3
输出
16
输入
2
1000000000 1000000000
输出
420352509
提示
子任务1: n <= 3 && max(R[i]) <= 100
子任务2: n <= 5 && max(R[i]) <= 1000
子任务3: 无限制

注: 题目在输入是有所不同的。
题解:

我们知道,在二进制数中,
和如果和等于或的话
那么只有两种情况:

(1) 多个数该二进制位的只有一个1.
(2) 多个数该二进制位的都没有1.

我们可以考虑数位dp
假设 d p [ i ] [ m a s k ] dp[i][mask] dp[i][mask] 表示已考虑i位之前的情况,当前的限制情况为mask.(其中第i为的1 或 0表示第 i 个数(从0开始算) 是否有限制,我们假定1为有限制,0 为没限制).
这题细节很多。
我们在代码中继续讲。topcoder上只需按照题目要求打包成一个类即可。

代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
using namespace std;
long long r[20];
const int mod = 1e9 + 9;
long long dp[65][1 << 11];
int n;
long long dfs(int w, int lim){//记忆化搜索,w表示当前第几位,lim是被限制的状态
	if(w < 0) return 1;//有一组A满足要求
	if(dp[w][lim] != -1) return dp[w][lim];
	int i, j, k;
	int now = 0;
	long long res = 0;
	//先考虑为一的情况
	for(i = 0; i < n; i++){ //枚举哪一个数该位为一,其他位为0
		now = 0;
		if((lim & (1 << i)) &&  !(r[i] & (1LL << w))) continue; //不可能为1(可能比较绕),就是有限制并且该二进制位最多为0
		for(j = 0; j < n; j++){//枚举每个数之后的限制情况
			if(i == j){//枚举到该位为一的数
				if(lim & (1 << i)){//注意特判,假如当前无限制,后面不可能有限制
					now |= (1 << j);
				}
			}
			else if((!(r[j] & (1LL << w))) && (lim & (1 << j))){//枚举到其他数,当前有限制,并且最高只能取0,后面任然会有限制
				now |= (1 << j);
			}
		}
		res = (res + dfs(w - 1, now)) % mod;
	}
	now = 0;
	for(i = 0; i < n; i++){ //枚举一位全为0
		if(!(r[i] & (1LL << w)) && (lim & (1 << i)))//当前有限制,并且最高只能取0,后面任然会有限制
			now |= (1 << i);
	}
	res = (res + dfs(w - 1, now)) % mod;//继续下一位
	dp[w][lim] = res;
	return res;
}
int main(){
	int i;
	scanf("%d", &n);
	for(i = 0; i < n; i++){
		scanf("%lld", &r[i]);
	}
	memset(dp, -1, sizeof(dp));
	printf("%lld\n", dfs(62, (1 << n) - 1));
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值