SRM 508 DIV1 500pt(DP)
2014-12-09 18:23
330 查看
题目简述
给定一个大小为 n的序列(n<=10)R,要求你计算序列A0, A1, ..., AN-1的数量,要求A序列满足A0 + A1 + ... + AN-1 = A0 | A1 | ... | AN-1(0<=Ai<=R[i])
题解
把n个数看成二进制,如果要求n个数的和等于n个数的或值,那么对于n个数的每一位,最多只可能有一个1,因为超过一个一就会产生进位。
由于第i个数如果当前位放置的是0,但 R[i]的当前位是1,那么之后的位置上就可以随意放了,没有限制,所以我们可以用DP[i][j]表示在第i位,当前状态为j的符合要求的方案数有多少(j的二进制中1表示放置的数没有限制,不然就是有限制),用记忆化搜索很好实现~~
代码:
给定一个大小为 n的序列(n<=10)R,要求你计算序列A0, A1, ..., AN-1的数量,要求A序列满足A0 + A1 + ... + AN-1 = A0 | A1 | ... | AN-1(0<=Ai<=R[i])
题解
把n个数看成二进制,如果要求n个数的和等于n个数的或值,那么对于n个数的每一位,最多只可能有一个1,因为超过一个一就会产生进位。
由于第i个数如果当前位放置的是0,但 R[i]的当前位是1,那么之后的位置上就可以随意放了,没有限制,所以我们可以用DP[i][j]表示在第i位,当前状态为j的符合要求的方案数有多少(j的二进制中1表示放置的数没有限制,不然就是有限制),用记忆化搜索很好实现~~
代码:
#define MOD 1000000009; ll dp[65][1111]; vector<ll>r; int n; ll DP(int i, int mask) { if (i == -1) return 1; ll &ret = dp[i][mask]; if(ret!=-1) return ret; ret=0; int next = mask; for (int t = 0; t < n; t++) if (r[t] & (1LL << i)) next |= (1 << t); ret += DP(i - 1, next); ret%=MOD; for (int t = 0; t < n; t++) if (mask & (1 << t)) { ret += DP(i - 1, next); ret %= MOD; } else if (r[t] & (1LL << i)) { ret += DP(i - 1, next ^ (1 << t)); ret %= MOD; } return ret; } class YetAnotherORProblem { public: int countSequences(vector<long long> R) { n = R.size(); r = R; memset(dp, -1, sizeof(dp)); return DP(60, 0); } };
相关文章推荐
- SRM 501 DIV1 500pt(DP)
- TC SRM 659 DIV1 500pt 插头DP
- SRM 502 DIV1 500pt(DP)
- SRM 509 DIV1 500pt(DP)
- SRM 514 DIV1 500pt(DP)
- SRM 511 DIV1 500pt(DP)
- Topcoder SRM 144 Div1 550(数学和dp问题求方案数,很有意思)
- SRM 602 D2L3:BlackBoxDiv2,dp
- srm 653 div2 1000(dp)
- srm 655 div2 1000(DP进阶,枚举状态)
- Topcoder SRM 663 Div2 Hard: CheeseRolling(状压DP)
- TopCoder SRM 648 Div2 Problem 1000 - ABC (DP)
- TopCoder SRM 666 Div2 Problem 999 - WalkOverATreeDiv2 (树形DP)
- Topcoder SRM 144 Div2 1100 (树形dp)
- SRM 607 D1 L1:PalindromicSubstringsDiv1,DP
- srm 654 div2 1000 (DP,最大连续和拓展, 有亮点)
- [补集转换 DP] Topcoder SRM 509 DIV1 Hard. NumberLabyrinthDiv1
- SRM 719 div1 Medium (树形dp)
- srm 301 div2 1000 (经典dp, 括号匹配)
- SRM 448 DIV 1 总结(dfs, dp)