..对于刚学dp的萌新十分不友好..
题目描述:你一个数组R,包含N个元素,求有多少满足条件的序列A使得0≤A[i]≤R[i].A[0]+A[1]+...+A[N-1]=A[0] or A[1]... or A[N-1]输出答案对1e9+9取模.
首先知道等式成立的条件是对于每一位分配的A[i],不可能存在2个1,也就是说最多分配一个1.然后就是介绍dp的含义了.
dp需要开两维dp[k][i],第一维是分配到了第k位,第二维是这些A[]前k-1位是不是与R[]相同,然后直接dfs即可.
冷静分析复杂度是60*(1<<10).
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=11,M=65;
const ll mod=1e9+9;
ll R[N];
int n;
ll dp[M][1<<N];
inline ll dfs(ll s,ll pos)//每个与前面相同情况,现在分配到了第pos位.
{
ll &ans=dp[pos][s];
if(pos<=0) return 1;
if(ans) return ans;
//先分配0.
int sp=s;
for(int i=0;i<n;i++)
{
if((s&(1<<i))&&(R[i]&(1ll<<(pos-1))))//假设这一位和R[i]的前pos-1位相同.
{
sp^=(1<<i);
}
}
ans=(ans+dfs(sp,pos-1))%mod;
//分配一个1.
for(int i=0;i<n;i++)
{
if((s&(1<<i)))
{
if(!(R[i]&(1ll<<(pos-1)))) continue;
ans=(ans+dfs(sp^(1ll<<i),pos-1))%mod;
}
else ans=(ans+dfs(sp,pos-1))%mod;
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%lld",&R[i]);
}
printf("%lld\n",dfs((1<<n)-1,60ll));
return 0;
}

京公网安备 11010502036488号