hdoj 4901 The Romantic Hero DP hdoj 4902 Nice boat 线段树

惨遭丽洁乱虐。。这一场也是比得乱七八糟的,4902本是丽洁定义比较难的题,结果数据随机的,被许多暴力水过了。。4905考察的是四边形不等式优化,但是这道题的dp方程实际上不满足该优化的条件。。朴素的o(n^3)会超时,所以这题目前是没有正解了。。我还写了个这题的贪心,强度挺高,可以对大概一半数据,错的误差也只有个位数,还揪出官方第五个数据。。朴素dp和贪心跑这个数据都比官方数据多了1,也就证明这题不满足四边形不等式优化的条件。。

http://acm.hdu.edu.cn/showproblem.php?pid=4901

看到每个数在0到1023,启发了dp思路。我们记录前i个数用xor组成0-1023的方案数,对应地乘上第i个数以后用and组成0-1023的方案数,累加即是答案。这样会有重复的问题,所以需要多开一个数组辅助。

f[i][j]是前i个数xor组成j的方案数,而且是必须取第i个数,这样保证S的子集不会重复计算,g[i][j]是前i个数xor组成j的方案数,h[i][j]是第i个数及以后and组成j的方案数。ans=ΣΣf[i][j]*h[i+1][j]即是答案。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5
 6 const long long mo = (long long)1e9 + 7;
 7 int n, T;
 8 int a[1100];
 9 long long f[1100][1100], g[1100][1100], h[1100][1100];
10 int main()
11 {
12     scanf("%d", &T);
13     while(T--)
14     {
15         scanf("%d", &n);
16         for (int i = 0; i < n; i++) scanf("%d", a+i);
17         memset(f, 0, sizeof(f));
18         memset(g, 0, sizeof(g));
19         memset(h, 0, sizeof(h));
20         for (int i = 0; i < n-1; i++){
21             f[i][a[i]] ++;
22             if (i == 0){
23                 g[i][a[i]] ++;
24                 continue;
25             }
26             for (int j = 0; j < 1024; j++)
27                 f[i][j] = (f[i][j] + g[i-1][j^a[i]]) % mo;    //xor同一个数两次相当于xor0
28             for (int j = 0; j < 1024; j++)
29                 g[i][j] = (g[i-1][j] + f[i][j]) % mo;
30         }
31         for (int i = n-1; i > 0; i--){
32             h[i][a[i]] ++;
33             if (i == n-1) continue;
34             for (int j = 0; j < 1024; j++)
35                 h[i][j&a[i]] = (h[i][j&a[i]] + h[i+1][j]) % mo;  //但是and不行。。和上面xor一样地写导致wa了几次。。
36             for (int j = 0; j < 1024; j++)
37                 h[i][j] = (h[i][j] + h[i+1][j]) % mo;
38         }
39         long long ans = 0;
40         for (int i = 0; i < n-1; i++)
41             for (int j = 0; j < 1024; j++)
42                 if (f[i][j] > 0)
43                     ans = (ans + f[i][j] * h[i+1][j]) % mo;
44         printf("%lld\n", ans);
45     }
46     return 0;
47 }

http://acm.hdu.edu.cn/showproblem.php?pid=4902

一只线段树,因为第一种操作是区间修改所有数为同一个数,打个标签,对于有标签的区间,第二种操作就只需要对一个数进行处理了。数据比较水,然后就水过了,丽洁的题解和标程我也看不太懂。。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5
  6 struct tree{
  7     int maxn;
  8     bool flag;
  9 }t[101000 << 2];
 10 int T, n, q;
 11 int a[101000];
 12 void pushup(int x)
 13 {
 14     t[x].maxn = max(t[x<<1].maxn, t[x<<1|1].maxn);
 15 }
 16 void pushdown(int x)
 17 {
 18     if (t[x].flag){
 19         t[x].flag = false;
 20         t[x<<1].maxn = t[x<<1|1].maxn = t[x].maxn;
 21         t[x<<1].flag = t[x<<1|1].flag = true;
 22     }
 23 }
 24 void build(int x, int l, int r)
 25 {
 26     t[x].flag = false;
 27     if (l == r){
 28         t[x].flag = true;
 29         t[x].maxn = a[l];
 30         return;
 31     }
 32     int mid = l + r >> 1;
 33     build(x<<1, l, mid);
 34     build(x<<1|1, mid+1, r);
 35     pushup(x);
 36 }
 37 void update(int x, int l, int r, int s, int e, int v)
 38 {
 39     if (s <= l && r <= e){
 40         t[x].flag = true;
 41         t[x].maxn = v;
 42         return;
 43     }
 44     pushdown(x);
 45     int mid = l + r >> 1;
 46     if (s <= mid)
 47         update(x<<1, l, mid, s, e, v);
 48     if (e > mid)
 49         update(x<<1|1, mid+1, r, s, e, v);
 50     pushup(x);
 51 }
 52 void trans(int x, int l, int r, int s, int e, int v)
 53 {
 54     if (t[x].maxn <= v) return;
 55     if (s <= l && r <= e && t[x].flag){
 56         t[x].maxn = __gcd(t[x].maxn, v);
 57         return;
 58     }
 59     if (l == r){
 60         t[x].maxn = __gcd(t[x].maxn, v);
 61         return;
 62     }
 63     pushdown(x);
 64     int mid = l + r >> 1;
 65     if (s <= mid)
 66         trans(x<<1, l, mid, s, e, v);
 67     if (e > mid)
 68         trans(x<<1|1, mid+1, r, s, e, v);
 69     pushup(x);
 70 }
 71 int query(int x, int l, int r, int p)
 72 {
 73     if (t[x].flag) return t[x].maxn;
 74     int mid = l + r >> 1;
 75     if (p <= mid) return query(x<<1, l, mid, p);
 76     else return query(x<<1|1, mid+1, r, p);
 77 }
 78 int main()
 79 {
 80     scanf("%d", &T);
 81     while(T--)
 82     {
 83         scanf("%d", &n);
 84         for (int i = 1; i <= n; i++)
 85             scanf("%d", a+i);
 86         build(1, 1, n);
 87         scanf("%d", &q);
 88         int type, l, r, x;
 89         for (int i = 0; i < q; i++){
 90             scanf("%d %d %d %d", &type, &l, &r, &x);
 91             if (type == 1)
 92                 update(1, 1, n, l, r, x);
 93             else
 94                 trans(1, 1, n, l, r, x);
 95         }
 96         for (int i = 1; i <= n; i++)
 97             printf("%d ", query(1, 1, n, i));
 98         puts("");
 99     }
100     return 0;
101 }

顺便把4905贪心贴出来吧,虽然过不了题= = 策略是优先合并相同的数(且不为0,比如0 0 5),然后合并gcd最大的数。说不定优化优化有朝一日会变成正解?= =。。

啊妈蛋刚才发现这道题都被下架了。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7
 8 long long ans;
 9 int T, n;
10 int a[3010];
11 int gcd(int a, int b)
12 {
13     if (b == 0) return a;
14     return gcd(b, a % b);
15 }
16 int main()
17 {
18     scanf("%d", &T);
19     while(T--)
20     {
21         ans = 0;
22         scanf("%d", &n);
23         for (int i = 1; i <= n; i++){
24             scanf("%d", a+i);
25             ans = ans + a[i];
26         }
27         int tot = n;
28         for (int i = 1; i <= n-1; i++){
29             int j, pos, tmp, tmp1;
30             for (j = 1; j <= tot-1; j++)
31                 if (a[j] == a[j+1] && a[j] != 0) break;
32             if (j == tot){
33                 tmp = 0;
34                 for (j = 1; j <= tot-1; j++){
35                     tmp1 = gcd(a[j], a[j+1]);
36                     if (tmp1 > tmp){
37                         tmp = tmp1;
38                         pos = j;
39                     }
40                 }
41                 j = pos;
42             }
43             else tmp = a[j];
44             ans = ans + tmp;
45             a[j] = tmp;
46             for (int k = j+1; k < tot; k++)
47                 a[k] = a[k+1];
48             tot --;
49         }
50         printf("%lld\n", ans);
51     }
52     return 0;
53 }

hdoj 4901 The Romantic Hero DP hdoj 4902 Nice boat 线段树

时间: 2024-10-27 03:19:09

hdoj 4901 The Romantic Hero DP hdoj 4902 Nice boat 线段树的相关文章

HDOJ 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): 547    Accepted Submission(s): 217 Problem Description There is an old country and the king fell in love with a

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

HDU 4902 Nice boat(线段树)

HDU Nice boat 题目链接 题意:给定一个序列,两种操作,把一段变成x,把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 思路:线段树,每个结点多一个cover表示该位置以下区间是否数字全相同,然后每次延迟操作,最后输出的时候单点查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1

多校第4场 HDU 4902 Nice boat 线段树

思路:这题比赛的时候宝哥说的思路我觉得对的,就是当是2操作的时候,先把数放到数组里,最后查询输出的时候再统一计算,不过那时敲得烂死了,debug了两天,靠-- 上午写的vector在pushDown的时候又忘了clear了,然后MLE了一早上,尼玛,还以为用的数组太大超了,然后又改成结构体,还是MLE,最后把别人的代码交上去发现没MLE,疯了一中午,最后无聊的时候才发现这个错误,尼玛--发现自己调试怎么变得这么弱了呢-- 还有一个需要注意的问题是1与2操作的处理上比较容易出错,这也是我WA了一下

HDU 4902 Nice boat 线段树+离线

据说暴力也过了.还傻逼地写了这么长. . . #include <stdio.h> #include <string.h> #include <math.h> #include <iostream> using namespace std; #define ll long long #define L(x) (x<<1) #define R(x) (x<<1|1) #define Val(x) tree[x].val #define

HDU 4902 Nice boat --线段树(区间更新)

题意:给一个数字序列,第一类操作是将[l,r]内的数全赋为x ,第二类操作是将[l,r]中大于x的数赋为该数与x的gcd,若干操作后输出整个序列. 解法: 本题线段树要维护的最重要的东西就是一个区间内所有数是否相等的标记.只维护这个东西都可以做出来. 我当时想歪了,想到维护Max[rt]表示该段的最大值,最大值如果<=x的话就不用更新了,但是好像加了这个“优化”跑的更慢了. 我想大概是因为如果两个子树最大值或者整个两个子树的数不完全相等的话,根本不能直接下传这个值或者下传gcd,因为你不知道要更

HDU 4901 The Romantic Hero(二维dp)

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

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