大意: 给定数组$R$, 求有多少个数组$A$, 满足$0le A_i le R_i$且$A_0+...+A_{N-1}=A_0space or ...space or space A_{N-1}$.
题目条件等价于对于任意的$i,j$, 有$A_i and A_j = 0$, 所以每个二进制位上为$1$的最多只有一个数, 然后跑一次二进制数位$dp$即可.
#include <iostream> #include <algorithm> #include <cstdio> #include <string.h> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) using namespace std; typedef long long ll; const int P = 1e9+9; int n, dp[70][2000]; ll r[20]; //dp[x][y] 表示从二进制最高位填到第d位时, 无限制的a[i]的状态为now的方案数. int dfs(int d, int now) { if (d<0) return 1; int &ans = dp[d][now]; if (~ans) return ans; int nxt = now; REP(i,0,n-1) if (r[i]>>d&1) nxt |= 1<<i; //第d位全为0的方案数 ans = dfs(d-1,nxt); REP(i,0,n-1) { //a[i]的第d位为1的方案数 if (now>>i&1) { //a[i]无限制, 则下一步全无限制 ans = (ans+dfs(d-1,nxt))%P; } else if (nxt>>i&1) { //a[i]有限制, 且r[i]的第d位为1, 则下一步a[i]还有限制 ans = (ans+dfs(d-1,nxt^(1<<i)))%P; } //a[i]有限制, 且r[i]的第d位为0, 不能填1 } return ans; } int main() { scanf("%d", &n); REP(i,0,n-1) scanf("%lld", r+i); memset(dp,-1,sizeof dp); printf("%d ", dfs(60,0)); }