2014多校第四场1005 || HDU 4901 The Romantic Hero (DP)

题目链接

题意 :给你一个数列,让你从中挑选一些数组成集合S,挑另外一些数组成集合T,要求是S中的每一个数在原序列中的下标要小于T中每一个数在原序列中下标。S中所有数按位异或后的值要与T中所有的数按位与的值相同,问能找出多少符合要求的组合。

思路 :比赛的时候有点没有头绪,后来二师兄想出了状态转移方程,YN又改了很多细节,最后才A的。总之是个别扭的DP。。。。。

一开始是 _xor[i][j^a[i]] += _xor[i-1][j] ;j 的下一个状态 就是异或上a[i],这个数组所代表的意思是,前 i 个数中选取某些数(必须包括 i )组成的集合按位异或得到j^a[i]

但是发现这样会重复,因为对于对于S和T的选取的元素,下标前后没有明显的界限,从前往后找与从后往前找,两厢重复。后来就重新设了一个数组去存以前的所有的值:

_xor[i][j^a[i]] += xort[i-1][j] ;
xort[i][j] = _xor[i][j] + xort[i-1][j] ;//这个表达式,代表这前 i 个中选取了某些数(必须选了 i )异或后的值为j的情况加上前 i -1个选某些值异或后的值为 j 。其实就是选与不选 i 的两种情况相加,组成的就是前 i 个中选取某些数异或出 j 所组成的情况,此时的 i 可选可不选。

 1 //4901
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <iostream>
 5 typedef long long  LL ;
 6 const long long mod = 1000000007 ;
 7 using namespace std ;
 8 
 9 int a[1050] ;
10 LL _xor[1050][1050],xort[1050][1050],_and[1050][1050],andt[1050][1050] ;
11 
12 void Init()
13 {
14     memset(_xor,0,sizeof(_xor)) ;
15     memset(xort,0,sizeof(xort)) ;
16     memset(_and,0,sizeof(_and)) ;
17     memset(andt,0,sizeof(andt)) ;
18     memset(a,0,sizeof(a)) ;
19 }
20 int main()
21 {
22     int T,n ;
23     cin >> T ;
24     while(T -- )
25     {
26         cin >> n ;
27         Init() ;
28         for(int i = 0 ; i < n ; i++)
29             cin >> a[i] ;
30         _xor[0][a[0]] = xort[0][a[0]] = 1 ;
31         for(int i = 1 ; i < n ; i++)
32         {
33             for(int j = 0 ; j < 1024 ; j ++)
34             {
35                 _xor[i][j^a[i]] += xort[i-1][j] ;
36                  _xor[i][j^a[i]]  %= mod ;
37             }
38             _xor[i][a[i]] ++ ;
39             for(int j = 0 ; j < 1024 ; j++)
40             {
41                 xort[i][j] = _xor[i][j] + xort[i-1][j] ;
42                 xort[i][j] %= mod ;
43             }
44         }
45         _and[n-1][a[n-1]] = andt[n-1][a[n-1]] = 1 ;
46         for(int i = n-2 ; i >= 0 ; i--)
47         {
48             for(int j = 0 ; j < 1024 ; j++)
49             {
50                 _and[i][j&a[i]] += andt[i+1][j] ;
51                 _and[i][j&a[i]] %= mod ;
52             }
53             _and[i][a[i]] ++ ;
54             for(int j = 0 ; j < 1024 ; j++){
55                 andt[i][j] = andt[i+1][j] + _and[i][j] ;
56                 andt[i][j] %= mod ;
57             }
58         }
59         LL ans = 0 ;
60         for(int i = 0 ; i < n-1 ; i++)
61         {
62             for(int j = 0 ; j < 1024 ; j++)
63             {
64                 ans += (_xor[i][j] * andt[i+1][j]) % mod ;
65                 ans %= mod ;
66             }
67         }
68         cout << ans << endl ;
69      }
70      return 0 ;
71 }
View Code

 

 

转载于:https://www.cnblogs.com/luyingfeng/p/3883654.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值