HDU--4901--The Romantic Hero

The Romantic Hero

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1112    Accepted Submission(s): 459


Problem Description
There is an old country and the king fell in love with a devil. The devil always asks the king to do some crazy things. Although the king used to be wise and beloved by his people. Now he is just like a boy in love and can’t refuse any request from the devil. Also, this devil is looking like a very cute Loli.

You may wonder why this country has such an interesting tradition? It has a very long story, but I won't tell you :).

Let us continue, the party princess's knight win the algorithm contest. When the devil hears about that, she decided to take some action.

But before that, there is another party arose recently, the 'MengMengDa' party, everyone in this party feel everything is 'MengMengDa' and acts like a 'MengMengDa' guy.

While they are very pleased about that, it brings many people in this kingdom troubles. So they decided to stop them.

Our hero z*p come again, actually he is very good at Algorithm contest, so he invites the leader of the 'MengMengda' party xiaod*o to compete in an algorithm contest.

As z*p is both handsome and talkative, he has many girl friends to deal with, on the contest day, he find he has 3 dating to complete and have no time to compete, so he let you to solve the problems for him.

And the easiest problem in this contest is like that:

There is n number a_1,a_2,...,a_n on the line. You can choose two set S(a_s1,a_s2,..,a_sk) and T(a_t1,a_t2,...,a_tm). Each element in S should be at the left of every element in T.(si < tj for all i,j). S and T shouldn't be empty.

And what we want is the bitwise XOR of each element in S is equal to the bitwise AND of each element in T.

How many ways are there to choose such two sets? You should output the result modulo 10^9+7.
 

Input
The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains a integers n.
The next line contains n integers a_1,a_2,...,a_n which are separated by a single space.

n<=10^3, 0 <= a_i <1024, T<=20.
 

Output
For each test case, output the result in one line.
 

Sample Input
  
  
2 3 1 2 3 4 1 2 3 3
 

Sample Output
  
  
1 4

题意:把这个数列取一些数分成两部分,要求x中所有数字都小于b中数字,求这些分配方案中,x里面的数全部“异或”起来的值等于y里面的数全部“与”起来的值相同的方案数,x和y中不能为空


做法,DP,用分割线的方法把数列分成两段,然后用x[i][j]来代表从开头知道第i个数字这些数字能组成的集合的总方案数,y[i][j]和x[i][j]差不多,但是有一点不同,就是当下标大于j的时候,x[j]中所有的方案x[i]中都存在,而在y[i]中,只记录和第i和数字进行了“与”运算的方案数,这样就不会重复了,因为我在y[i][j]的时候是和x[i-1][j]匹配,x[i-1][j]然后分割线左移的任何的x[i1][j1]的方案在x[i][j]中都有,所以我只在这个时候匹配一次

例如:

4

1 2 3 3

x[1]={1}

x[2]={1,2,1^2}

x[3]={1,2,3,1^2,1^3,2^3,1^2^3}

x[4]就不用计算了,因为去了第四个数字那么y里面就为空,违反条件了


y[4]={3}

y[3]={3,3&3} //这里的3是第三个数字的3,第四个数字的三在y[4]中出现并且已经与x[3]匹配过了,y[3]里面是从最后一个数字到第三个数字中和第三个数字3与运算得到的方案

y[2]={2,2&3,2&3&3}


在y[4]和x[3]匹配的时候就等于把y[4]与x[2]、y[4]与x[1]都匹配完了,毕竟x[3]包含了x[2],x[1]中所有的方案嘛

然后这个y[4]的方案就不用传递给y[3]了,不然又要与x[2],x[1]去匹配,这样就重复了,但是还是要保存式记录下来,因为前面随便一个数字都可以和它形成一个新的集合


这个题谁会相信我做了一天?当初要了解题意的时候找博客,结果只有三条,现在一下子就成几页了,而且我一直WA在一个代码,却在博客看到了一个和自己一模一样的代码,你应该要知道这种情况下我会怀疑他的也是WA,结果他的AC,我看了2小时都没看出所以然,结果让别人一看。。。我滴天那,1024我写成了1014,我擦你妹妹蛋蛋的,天坑


#include <iostream>
#include <cstdio>
#include <cstring>
#define LL __int64
#define mod 1000000007
using namespace std;
LL x[1111][2222],y[1111][2222];	//x:分割线左边,y:分割线右边,如x[i][j]代表分割线在第i个数字和i+1个数字中间时候的异或结果是j的方案数
int main (void)
{
    int t,n,i,j,k,l;
    int s[1010];
    scanf("%d",&t);
    while(t--&&scanf("%d",&n))
    {
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&s[i]);
            x[i][s[i]]=1;	//单个元素也算一个方案
            for(j=0;j<1024;j++)	//遍历所有值,把前一条分割线的方案全部异或到当前分割线的方案中来
            {
                x[i][j]=(x[i][j]+x[i-1][j])%mod;	//传递方案数,这就是x[i]包含了所有x[i-j](j>0)中方案数的原因
                x[i][j^s[i]]=(x[i][j^s[i]]+x[i-1][j])%mod;	//把这些方案异或当前的这个值得到的新的方案存起来
            }
        }
        LL sum=0;
        for(i=n;i>1;i--)
        {
            y[i][s[i]]=1;	//单个元素也算一个方案
            for(j=0;j<1024;j++)	//遍历所有值
            if(y[i+1][j])	//如果这个值为j的方案数存在
            y[i][j&s[i]]=(y[i][j&s[i]]+y[i+1][j])%mod;	//那么把这个方案跟当前元素与运算之后得到新方案
            for(j=0;j<1024;j++)	//把得到的所有新方案加起来
            sum=(sum+x[i-1][j]*y[i][j])%mod;
            for(j=0;j<1024;j++)	//把先前的旧方案传递过来
            y[i][j]=(y[i][j]+y[i+1][j])%mod;
        }
        printf("%I64d\n",sum);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值