Bestcoder Round#45

1001

给定数n,要我们求该数的二进制中有多少组1, 相邻的1称为1组, 直接位运算摸你即可

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <algorithm>
 5 #include <iostream>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <map>
10 #include <set>
11 #include <string>
12 #include <math.h>
13 using namespace std;
14 #pragma warning(disable:4996)
15 typedef long long LL;                   
16 const int INF = 1<<30;
17 /*
18 
19 */
20 
21 int main()
22 {
23     int t;
24     LL n;
25     scanf("%d", &t);
26     while (t--)
27     {
28         scanf("%I64d", &n);
29         int ans = 0;
30         bool flag = true;
31         while (n)
32         {
33             if ((n & 1))
34             {
35                 if (flag)
36                 {
37                     ans++;
38                     flag = false;
39                 }
40             }
41             else
42                 flag = true;
43 
44             n >>= 1;
45         }
46         printf("%d
", ans);
47     }
48     return 0;
49 }
View Code

1002

比赛的时候,一直认为求逆序对,要用树状数组做, 就YY出了一个树状数组的解法。

我把询问按照L从小到大排序,然后分为两种情况

对于第一种情况,我们只要将左边的数从树状数组中减去,然后加上右边的数即可。

对于第二种情况,我们将数状数组情况, 重新建树状数组

其实比赛完之后,仔细想想,如果存在很多第二种情况(应该最多只有1000种,因为N<=1000) , 那么时间复杂度是N*N*logN, 应该是勉强可以过, 或者直接TLE

不过自己YY出来这种想法, 还是挺好的。

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <algorithm>
  5 #include <iostream>
  6 #include <queue>
  7 #include <stack>
  8 #include <vector>
  9 #include <map>
 10 #include <set>
 11 #include <string>
 12 #include <math.h>
 13 using namespace std;
 14 #pragma warning(disable:4996)
 15 typedef long long LL;                   
 16 const int INF = 1<<30;
 17 /*
 18 
 19 */
 20 struct Node
 21 {
 22     int l, r;
 23     int id;
 24     bool operator<(const Node &rhs)const
 25     {
 26         if (l == rhs.l)
 27             return r < rhs.r;
 28         return l < rhs.l;
 29     }
 30 }Q[100000+10];
 31 int a[1000 + 10];
 32 int b[1000 + 10];
 33 map<int, int> mark;
 34 int ans[100000 + 10];
 35 int sum[1000 + 10];
 36 int lowbit(int x)
 37 {
 38     return x & (-x);
 39 }
 40 void modify(int pos, int val, int n)
 41 {
 42     while (pos <= n)
 43     {
 44         sum[pos] += val;
 45         pos += lowbit(pos);
 46     }
 47 }
 48 int getSum(int pos)
 49 {
 50     int ret = 0;
 51     while (pos > 0)
 52     {
 53         ret += sum[pos];
 54         pos -= lowbit(pos);
 55     }
 56     return ret;
 57 }
 58 int main()
 59 {
 60     int n, q;
 61     while (scanf("%d%d", &n, &q) != EOF)
 62     {
 63         memset(sum, 0, sizeof(sum));
 64         for (int i = 0; i < n; ++i)
 65         {
 66             scanf("%d", &a[i]);
 67             b[i] = a[i];
 68         }
 69         for (int i = 0; i < q; ++i)
 70         {
 71             scanf("%d%d", &Q[i].l, &Q[i].r);
 72             Q[i].l--;
 73             Q[i].r--;
 74             Q[i].id = i;
 75         }
 76         sort(a, a + n);
 77         sort(Q, Q + q);
 78         n = unique(a, a + n) - a;
 79         //printf("%d
", n);
 80         for (int i = 0; i < n; ++i)
 81         {
 82             mark[a[i]] = i + 1;
 83             //printf("%d %d
", a[i], i + 1);
 84         }
 85         int preL = 0;
 86         int preR = 0;
 87         int t;
 88         int tmp = 0;
 89         for (int i = 0; i < q; ++i)
 90         {
 91             if (preR - 1 > Q[i].r)//第二种情况, 清空树状数组
 92             {
 93                 memset(sum, 0, sizeof(sum));
 94                 preR = Q[i].l;
 95                 preL = Q[i].l;
 96                 tmp = 0;
 97             }
 98             for (int j = preL; j < Q[i].l; ++j)//减去左边的区间
 99             {
100                 tmp -= getSum(mark[b[j]]-1);
101                 modify(mark[b[j]], -1, mark[a[n - 1]]);
102                 preL = Q[i].l;
103                 
104             }
105             
106             for (int j = preR; j <= Q[i].r; ++j)
107             {
108                 
109                 modify(mark[b[j]], 1, mark[a[n-1]]);
110                 tmp += getSum(mark[a[n-1]])-getSum(mark[b[j]]);
111             }
112             preR = Q[i].r + 1;
113             ans[Q[i].id] = tmp;
114         }
115         for (int i = 0; i < q; ++i)
116             printf("%d
", ans[i]);
117     }
118     return 0;
119 }
View Code

正解应该是。

设ans1[i][j] 为区间i-->j,包含a[i]的逆序对数,  首先我们暴力算好ans1[i][j] ,时间复杂度为O(N*N)

设ans2[i][j] 为区间i-->j中的逆序对数,

那么ans2[i][j] = ans1[i][j] + ans[i+1][j] +...+ans[j][j]

优化一下就是, 如果ans2[i+1][j] 已经算好了,  那么ans2[i][j] = ans2[i+1][j] + ans1[i][j];

所以这个的时间复杂度也是O(N*N),而且 ans1 和ans2可以合成一个数组

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include <algorithm>
 5 #include <iostream>
 6 #include <queue>
 7 #include <stack>
 8 #include <vector>
 9 #include <map>
10 #include <set>
11 #include <string>
12 #include <math.h>
13 using namespace std;
14 #pragma warning(disable:4996)
15 typedef long long LL;                   
16 const int INF = 1<<30;
17 /*
18 
19 */
20 const int N = 1000 + 10;
21 int ans[N][N]; 
22 int a[N];
23 int main()
24 {
25     int n, q;
26     while (scanf("%d%d", &n, &q) != EOF)
27     {
28         for (int i = 1; i <= n; ++i)
29             scanf("%d", &a[i]);
30 
31         //这里的ans[i][j] 表示区间i-->j, 包含元素a[i]的逆序对数
32         for (int i = 1; i <= n; ++i)
33         for (int j = i; j <= n; ++j)
34             ans[i][j] += ans[i][j - 1] + (a[i] > a[j] ? 1 : 0);
35 
36         //那么 ans[i][j] 要表示区间i-->j的逆序对数时, ans[i][j] += ans[i+1][j] + ans[i+2][j]+...+ans[j][j]
37         // 如果ans[i+1][j]已经算出来了,  那么ans[i][j] += ans[i+1][j] 即可,  因为贡献是后缀和性质的
38         for (int j = 1; j <= n; ++j)
39         for (int i = j; i >= 1; --i)
40             ans[i][j] += ans[i + 1][j];
41         int l, r;
42         while (q--)
43         {
44             scanf("%d%d", &l, &r);
45             printf("%d
", ans[l][r]);
46         }
47     }
48     return 0;
49 }
View Code

1003

给我们一棵树,每个节点都有权值, 有两个操作

0 x y ,  将节点x的权值改为y

1 x y   询问x->y 的路径上, 是否有权值的次数出现奇数次(保证最多只有一个奇数次) 如果没有,输出-1, 如果有, 输出那个权值

任意两点的路径, 可以用lca求出, 然后要求权值是不是出现奇数次, 可以用异或,   a^a = 0  ,  a^a^a=a,

然而这并没有什么用,TLE, 如果树退化成链, 那么每次询问的时间复杂度是O(N),每次询问的复杂度要O(logN)才行

  1 #pragma comment(linker, "/STACK:102400000,102400000")
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5 #include <algorithm>
  6 #include <iostream>
  7 #include <queue>
  8 #include <stack>
  9 #include <vector>
 10 #include <map>
 11 #include <set>
 12 #include <string>
 13 #include <math.h>
 14 using namespace std;
 15 #pragma warning(disable:4996)
 16 typedef long long LL;                   
 17 const int INF = 1<<30;
 18 /*
 19 RE
 20 */
 21 const int N = 100000 + 10;
 22 struct Edge
 23 {
 24     int to, next;
 25 }g[N];
 26 
 27 int value[N], head[N], e, parent[N], depth[N];
 28 void addEdge(int a, int b)
 29 {
 30     g[e].to = b;
 31     g[e].next = head[a];
 32     head[a] = e++;
 33 }
 34 void dfs(int u, int fa, int d)
 35 {
 36     depth[u] = d;
 37     for (int i = head[u]; i != -1; i = g[i].next)
 38     {
 39         int v = g[i].to;
 40         if (v == fa) continue;
 41         dfs(v, u,d + 1);
 42     }
 43 }
 44 
 45 int solve(int x, int y)
 46 {
 47     if (x == y)
 48         return value[x];
 49     int ret = 0;
 50     ret ^= value[x];
 51     //ret ^= value[y];
 52     if (depth[x] < depth[y])
 53         swap(x, y); 
 54     int t = y;
 55     int d = depth[x];
 56     while(d > depth[y])
 57     {
 58         x = parent[x];
 59         d--;
 60         ret ^= value[x];
 61     }
 62     while (x!=y)
 63     {
 64         x = parent[x];
 65         y = parent[y];
 66         ret ^= value[x];
 67         ret ^= value[y];
 68     }
 69     if (t != y)
 70         ret ^= value[y];
 71     return ret;
 72 
 73 }
 74 int main()
 75 {
 76     int t, n, q, a, b, op;
 77     scanf("%d", &t);
 78     while (t--)
 79     {
 80         memset(parent, -1, sizeof(parent));
 81         memset(depth, 0, sizeof(depth));
 82         memset(head, -1, sizeof(head));
 83         e = 0;
 84         scanf("%d%d", &n, &q);
 85         for (int i = 1; i < n; ++i)
 86         {
 87             scanf("%d%d", &a, &b);
 88             addEdge(a, b);
 89             addEdge(b, a);
 90             parent[b] = a;
 91 
 92         }
 93         int root = 1;
 94         while (parent[root] != -1)
 95             root = parent[root];
 96         dfs(root,-1,1);
 97         for (int i = 1; i <= n; ++i)
 98         {
 99             scanf("%d", &value[i]);
100             value[i]++;
101         }
102         for (int i = 0; i < q; ++i)
103         {
104             scanf("%d%d%d", &op, &a, &b);
105             if (op == 0)
106                 value[a] = b;
107             else
108             {
109                 int ret = solve(a, b);
110                 printf("%d
", ret ? ret-1 : -1);
111             }
112         }
113     }
114     return 0;
115 }
View Code

题解说这题要用树链剖分, 然后我并不懂

原文地址:https://www.cnblogs.com/justPassBy/p/4591701.html