HDU 4901(杭电多校训练#3 1005题)The Romantic Hero(DP)

题目地址:HDU 4901

这题没想到最后居然能够做出来。。。。

这题用了两次DP,先从前往后求一次异或的,再从后往前求一次与运算的。分别是

1:求异或的时候,定义二维数组huo[1000][1024],前者指第几位,后者是哈希的思想,若huo[x][y]=2则表示最右边的数为第x位时,异或值为y的出现了两次,需要再定义一个hash数组,来保存前面出现的所有情况,再找有多少位的时候,用hash数组中出现的所有的值与当前的第x位的数字进行异或。

2:求与的时候,定义二维数组yu[1000][1024],同异或的差不多,不过这里的位数是指从这位往后的所有的情况,而异或的是指必须包含该位。由于与运算本身就是求的所有的情况,不用再定义hash数组。

3:然后从前往后开始匹配,只要用huo[x]与yu[x+1]进行匹配就好了。如果两者出现了相同的异或值,那就将次数相乘。最终的答案即是正确答案。

注意;在运算的过程中数组里的数会出现爆long long的情况。。所以需要每一步都要求余。。(因为这个而错了好几次。。)

代码如下;

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
__int64 huo[1003][1125], yu[1003][1125], a[1013], _hash[1003][1030];
const int mod=1e9+7;
int main()
{
    __int64 t, n, i, j, k;
    __int64 s;
    scanf("%I64d",&t);
    while(t--)
    {
        s=0;
        memset(huo,0,sizeof(huo));
        memset(yu,0,sizeof(yu));
        scanf("%I64d",&n);
        for(i=1; i<=n; i++)
        {
            scanf("%I64d",&a[i]);
        }
        memset(_hash,0,sizeof(_hash));
        for(i=1; i<=n; i++)
        {
            for(j=0; j<=1024; j++)
            {
                if(_hash[i-1][j])
                {
                    _hash[i][a[i]^j]+=_hash[i-1][j];
                    _hash[i][a[i]^j]%=mod;
                    huo[i][a[i]^j]+=_hash[i-1][j];
                    huo[i][a[i]^j]%=mod;
                    _hash[i][j]+=_hash[i-1][j];
                    _hash[i][j]%=mod;
                }
            }
            _hash[i][a[i]]++;
            huo[i][a[i]]++;
        }
        for(i=n; i>=1; i--)
        {
            for(j=0; j<=1024; j++)
            {
                if(yu[i+1][j])
                {
                    yu[i][a[i]&j]+=yu[i+1][j];
                    yu[i][a[i]&j]%=mod;
                    yu[i][j]+=yu[i+1][j];
                    yu[i][j]%=mod;
                }
            }
            yu[i][a[i]]++;
        }
        for(i=1; i<=n; i++)
        {
            for(j=0; j<=1024; j++)
            {
                if(huo[i][j]&&yu[i+1][j])
                {
                    s=(s+huo[i][j]*yu[i+1][j])%mod;
                }
            }
        }
        printf("%I64d\n",s);
    }
    return 0;
}

HDU 4901(杭电多校训练#3 1005题)The Romantic Hero(DP)

时间: 2024-12-28 09:48:05

HDU 4901(杭电多校训练#3 1005题)The Romantic Hero(DP)的相关文章

HDU 4920(杭电多校训练#5 1010 题) Matrix multiplication(不知道该挂个什么帽子。。。)

题目地址:HDU 4920 对这个题简直无语到极点...居然O(n^3)的复杂度能过....方法有三.. 1:进行输入优化和输出优化..(前提是你的输入优化不能太搓...) 2:利用缓存优化..详情请看该论文.大体就是将后两个for循环换过来,让坐标改变的频率降下来. 3:叉姐题解中说的正规方法..利用biset存储,进行预处理..(其实我还没看懂.. 我只写了个第二种...代码如下,共勉..神奇的小代码.. #include <iostream> #include <cstdio>

HDU 4864 Task (贪心+STL多集(二分)+邻接表存储)(杭电多校训练赛第一场1004)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4864 解题报告:有n台机器用来完成m个任务,每个任务有一个难度值和一个需要完成的时间,每台机器有一个可以工作的最长时间和一个可以完成的任务的难度的最大值, 一台机器能完成一个任务的条件是这台机器的最长工作时间和能完成任务的难度值必须都大于等于这个任务,而且一台机器最多完成一个任务,假设一个任务的时间为t,难度值为x,那么完成这个任务可以赚到的钱 money = 500 * t + 2 * x; 现在

HDU 4902 Nice boat 2014杭电多校训练赛第四场F题(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4902 解题报告:输入一个序列,然后有q次操作,操作有两种,第一种是把区间 (l,r) 变成x,第二种是把区间 (l,r) 中大于x的数跟 x 做gcd操作. 线段树区间更新的题目,每个节点保存一个最大和最小值,当该节点的最大值和最小值相等的时候表示这个区间所有的数字都是相同的,可以直接对这个区间进行1或2操作, 进行1操作时,当还没有到达要操作的区间但已经出现了节点的最大值跟最小值相等的情况时,说明

HDU 4941 Magical Forest(map映射+二分查找)杭电多校训练赛第七场1007

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4941 解题报告:给你一个n*m的矩阵,矩阵的一些方格中有水果,每个水果有一个能量值,现在有三种操作,第一种是行交换操作,就是把矩阵的两行进行交换,另一种是列交换操作,注意两种操作都要求行或列至少要有一个水果,第三种操作是查找,询问第A行B列的水果的能量值,如果查询的位置没有水果,则输出0. 因为n和m都很大,达到了2*10^9,但水果最多一共只有10^5个,我的做法是直接用结构体存了之后排序,然后m

HDU 4937 (杭电多校 #7 1003题)Lucky Number(瞎搞)

题目地址:HDU 4937 多校的题以后得重视起来...每道题都错好多次...很考察细节.比如这道....WA了无数次.... 这题的思路自己真心想不到...这题是将进制后的数分别是1位,2位,3位和更多位的分开来计算. 当是1位的时候,显然只有3到6,此时只能是-1 当是2位的时候,可以转换成一元一次方程求解 当是3位的时候,可以转换成一元二次方程求解 当是4位的时候,此时最多也只有7000个数,7000^3接近1e12.所以剩下的直接枚举进制数来判断即可. 代码如下: #include <i

HDU 4975 (杭电多校 #10 1005题)A simple Gaussian elimination problem.(网络流之最大流)

题目地址:HDU 4975 对这题简直无语...本来以为这题要用什么更先进的方法,结果还是老方法,这么卡时间真的好吗....比赛的时候用了判环的方法,一直TLE..后来换了矩阵DP的方式,加了加剪枝就过了..无语了.. 代码如下: #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <cstdio> #include <

HDU 4888 (杭电多校#3)Redraw Beautiful Drawings(网络流之最大流)

题目地址:HDU 4888 自己之所以弱真心是态度的问题,以后不能再偷懒了!!那次这个题一直没补,结果这次又遇到了..还有这次遇到的最小割权闭合问题,也一直没刷,所以这次遇到了也不会,连是最小割都不知道!!(突然想起来前面还有好多题拖到现在也没做...T U T)以后绝不能再拖拉了! 这题的建图是很容易的,主要是判断唯一性不好判断.这里是用的dfs找环来判断是否唯一,因为假如有环的话,说明环 中的数字是可以相互流动而且可以保证解依然正确.. 代码如下: #include <cstdio> #i

HDU 4970(杭电多校#9 1011题)Killing Monsters(瞎搞)

题目地址:HDU 4970 先进行预处理,在每个炮塔的火力范围边界标记一个点.然后对每个点的伤害值扫一遍就能算出来.然后在算出每个点到终点的总伤害值,并保存下来,也是扫一遍即可.最后在询问的时候直接判断即可,复杂度O(2*n). 代码如下: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define maxn 110000 #define LL __int6

HDU 4961(杭电多校#9 1002题)Boring Sum(瞎搞)

题目地址:HDU 4961 看来这题的测试数据是随机的.不然出了极限数据还真过不了...这题我的方法是建一个哈希结构体,记录两个变量,分别是num位置,然后是f,f==0表示这个数没出现过,f==1表示这个数出现过.然后分别从前面和后面扫一遍.每次扫的时候,对每一个出现的数都进行标记.然后对当前的数枚举该数的倍数,全部枚举完,取位置num最大的.然后找完之后,对哈希结构体进行更新.如果前面曾经出现过的话,就直接换掉,因为后面的数总比前面的更优.最后扫完两遍之后两个数组就能求出来了.计算就行了.