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.
Class: YetAnotherORProblem
Method: countSequences
Parameters: long[]
Returns: int
Method signature: int countSequences(long[] R)
(be sure your method is public)
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[N−1] = A [ 0 ] A[0] A[0] | A [ 1 ] A[1] A[1]… | A [ N − 1 ] A[N-1] A[N−1]
输出答案对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: 无限制
我们知道,在二进制数中,
和如果和等于或的话
那么只有两种情况:
我们可以考虑数位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
#include
#include
#include
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;
}