hdoj 4901 多校联合4 1005

计数DP,思路还是很清晰的。只要有点DP基础,或者做过类似问题的,应该都能看出来是DP,可惜当时我没有做这个题。一直被那个线段树困着。

也希望以后能把线段树种活。这个题的思路就是设f[i][j]为 前i个数(从中选若干个数)异或值为j的集合数。h[i][j]为从第i个数开始到n(选若干个数),相与值为j的集合数。

最后两层循环(f[i][j]-f[i-1][j])*h[i+1][j]的累加和就是结果,之所以要减去f[i-1][j]是要去除重复的集合数。

代码如下:

#include
#include
#include
#include
using namespace std;
#define MAX 1111
#define MOD 1000000007
__int64 f[MAX][MAX],h[MAX][MAX];
int n,T;
int a[MAX];
int main()
{
    int i,j;
    scanf("%d",&T);
    while(T)
    {
        memset(f,0,sizeof(f));
        memset(h,0,sizeof(h));
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(i=1;i<=n;i++)
        {
            f[i][a[i]]++;
            for(j=0;j<1024;j++)
            {
                if(f[i-1][j])
                {
                    f[i][j]+=f[i-1][j];
                    f[i][j]%=MOD;
                    f[i][j^a[i]]+=f[i-1][j];
                    f[i][j^a[i]]%=MOD;
                }
            }
        }
        for(i=n;i>=1;i--)
        {
            h[i][a[i]]++;
            for(j=0;j<1024;j++)
            {
                 if(h[i+1][j])
                {
                    h[i][j]+=h[i+1][j];
                    h[i][j]%=MOD;
                    h[i][j&a[i]]+=h[i+1][j];
                    h[i][j&a[i]]%=MOD;
                }
            }
        }
        __int64 ans=0;
        for(i=1;i


 

你可能感兴趣的:(DP)