HDU - 4901 The Romantic Hero(dp)

https://vjudge.net/problem/HDU-4901

题意

给n个数,构造两个集合,使第一个集合的异或和等于第二个集合的相与和,且要求第一个集合的元素下标都小于第二个集合的元素下标。问方案数

分析

dp来做。dp1[i][j]表示0~i的元素异或和为j的个数。dp2[i][j]表示i~n-1的元素相与和为j的个数。注意状态转移时要同时计算第i个数参与或不参与的情况,且dp1的第一维不能取到n-1,类似的,dp2的第一维不能取0。统计最终答案时需要合并,那么怎么才能防止重复呢?这时再添加dp3[i][j]表示i~n-1的元素相与和为j的个数(i在集合中)。这样枚举i时,就能保证不重复不遗漏了。

#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>

#define rep(i,e) for(int i=0;i<(e);i++)
#define rep1(i,e) for(int i=1;i<=(e);i++)
#define repx(i,x,e) for(int i=(x);i<=(e);i++)
#define X first
#define Y second
#define PB push_back
#define MP make_pair
#define mset(var,val) memset(var,val,sizeof(var))
#define scd(a) scanf("%d",&a)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define pd(a) printf("%d\n",a)
#define scl(a) scanf("%lld",&a)
#define scll(a,b) scanf("%lld%lld",&a,&b)
#define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
#define IOS ios::sync_with_stdio(false);cin.tie(0)

using namespace std;
typedef long long ll;
template <class T>
void test(T a){cout<<a<<endl;}
template <class T,class T2>
void test(T a,T2 b){cout<<a<<" "<<b<<endl;}
template <class T,class T2,class T3>
void test(T a,T2 b,T3 c){cout<<a<<" "<<b<<" "<<c<<endl;}
const int N = 1e6+10;
//const int MAXN = 210;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const ll mod = 1000000007;
int T;
void testcase(){
    printf("Case #%d: ",++T);
}
const int MAXN = 1025;
const int MAXM = 30;
int dp1[MAXN][MAXN], dp2[MAXN][MAXN], dp3[MAXN][MAXN];
int a[MAXN];

int main(){
#ifdef LOCAL
    freopen("data.in","r",stdin);
#endif // LOCAL
    int T, n, i, j, t;
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        for(i = 0; i < n; i++)
            scanf("%d",&a[i]);
        memset(dp1, 0, sizeof(dp1));
        memset(dp2, 0, sizeof(dp2));
        memset(dp3, 0, sizeof(dp3));
        dp1[0][a[0]] = 1;
        for(i = 1; i < n - 1; i++) {
            dp1[i][a[i]]++; //单独一个元素构成一个集合
            for(j = 0; j < MAXN; j++) {
                if(dp1[i-1][j]) {
                    dp1[i][j] += dp1[i-1][j]; //不添加第i个元素进行异或,继承之前算好的
                    dp1[i][j] %= mod;

                    t = j ^ a[i];  //添加第i个元素进行异或
                    dp1[i][t] += dp1[i-1][j];
                    dp1[i][t] %= mod;
                }
            }
        }
        dp2[n-1][a[n-1]] = 1;
        dp3[n-1][a[n-1]] = 1;
        for(i = n-2; i > 0; i--) {
            dp2[i][a[i]]++;
            dp3[i][a[i]]++;   //单独一个元素构成一个集合
            for(j = 0; j < MAXN; j++) {
                if(dp2[i+1][j]) {
                    dp2[i][j] += dp2[i+1][j];  //不添加第i个元素进行按位与
                    dp2[i][j] %= mod;

                    t = j & a[i]; //添加第i个元素进行按位与
                    dp2[i][t] += dp2[i+1][j];
                    dp2[i][t] %= mod;

                    dp3[i][t] += dp2[i+1][j]; //添加第i个元素进行按位与
                    dp3[i][t] %= mod;
                }
            }
        }
        int ans = 0;
        for(i = 0; i < n - 1; i++) {
            for(j = 0; j < MAXN; j++) {
                if(dp1[i][j] && dp3[i+1][j]) {
                    ans += (ll(dp1[i][j]) * dp3[i+1][j] % mod);
                    ans %= mod;
                }
            }
        }
        printf("%d\n", ans);

    }
    return 0;
}

原文地址:https://www.cnblogs.com/fht-litost/p/9298096.html

时间: 2024-08-05 14:26:15

HDU - 4901 The Romantic Hero(dp)的相关文章

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],这个数组所代表的意思

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][102

hdu 4901 The Romantic Hero(计数dp)2014多校训练第4场1005

The Romantic Hero                                                                               Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description There is an old country and the king fell in lov

hdu 4901 The Romantic Hero 计数dp,位计算

The Romantic Hero Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 1128    Accepted Submission(s): 469 Problem Description There is an old country and the king fell in love with a devil. The d

HDU 4901 The Romantic Hero(DP)

HDU 4901 The Romantic Hero 题目链接 题意:给定一个序列,要求找一个分界点,然后左边选一些数异或和,和右边选一些数且和相等,问有几种方法 思路:dp,从左往右和从右往左dp,求出异或和且的个数,然后找一个分界点,使得一边必须在分界点上,一边随意,然后根据乘法原理和加法原理计算 代码: #include <cstdio> #include <cstring> typedef __int64 ll; const int N = 1024; const int

HDU 4901 The Romantic Hero(二维dp)

题目大意:给你n个数字,然后分成两份,前边的一份里面的元素进行异或,后面的一份里面的元素进行与.分的时候按照给的先后数序取数,后面的里面的所有的元素的下标一定比前面的大.问你有多上种放元素的方法可以使得前面异或的值和后面与的值相等. dp[x][y] 表示走到第x步,得到y这个数字一共有多少种方法. 但是需要注意这里得分一下,不能直接用dp数组存种数,你需要分一下从上一层过来的次数,和这一层自己可以到达的次数.然后取和的时候前后两个集合的种数进行乘法,注意边乘边取余. 顺便给一组数据: 4 3

hdu 4901 The Romantic Hero (dp+背包问题)

题意: 有n个数,从n个数中选出两个集合s和集合t,保证原序列中,集合s中的元素都在 集合t中元素的左边.且要求集合s中元素做抑或运算的值与集合t中元素做与运算的 值相等.问能选出多少种这样的集合s和t. 算法: 左右dp. 用dp[i][j]表示前i个数 做抑或运算得到j的方法数.最后一个值取不取到都不一定. 故为背包的问题.右边也是一样. 枚举时可能出现重复.枚举到第i个和枚举第i+1个可能重复.所以要枚举一个中间值. 这个中间值是归到s集的,因为抑或支持逆运算,而与是不支持的. 所以最后d

hdu 5623 KK&#39;s Number(dp)

问题描述 我们可爱的KK有一个有趣的数学游戏:这个游戏需要两个人,有N\left(1\leq N\leq 5*{10}^{4} \right)N(1≤N≤5∗10?4??)个数,每次KK都会先拿数.每次可以拿任意多个数,直到NN个数被拿完.每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大.在这样的情况下,最终KK的得分减去对手的得分会是多少? 输入描述 第一行一个数T\left( 1\leq T\leq 10\right)T(1≤T≤10),表示数据组

HDU 4968 Improving the GPA(dp)

HDU 4968 Improving the GPA 题目链接 dp,最大最小分别dp一次,dp[i][j]表示第i个人,还有j分的情况,分数可以减掉60最为状态 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int t, avg, n; double dp1[15][405], dp2[15][405]; double get(int x) { if