首页 > 代码库 > hdoj 4901 The Romantic Hero DP hdoj 4902 Nice boat 线段树

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同一个数两次相当于xor028             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 }