【luogu P4462 [CQOI2018]异或序列】 题解

本文提供洛谷P4462题目的一种解题思路,采用莫队算法处理区间查询问题,通过预处理及巧妙的数据结构设计实现高效求解。

题目链接:https://www.luogu.org/problemnew/show/P4462

ax+ax-1+...+ay = cntx+cnty 这样把一段序列变成两段相加跑莫队。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cmath>
 5 using namespace std;
 6 const int maxn = 200010;
 7 int curR = 0, curL = 1, answer,a[maxn], ans[maxn], cnt[maxn], n, m, k, bl;
 8 struct query{
 9     int l,r,p;
10 }q[maxn];
11 
12 bool cmp(const query &a, const query &b)
13 {
14     return (a.l/bl) == (b.l/bl) ? a.r<b.r : a.l<b.l;
15 }
16 
17 inline void add(int pos)
18 {
19     cnt[a[pos]]++;
20     answer+=cnt[a[pos]^k];
21 }
22 
23 inline void remove(int pos)
24 {
25     cnt[a[pos]]--;
26     answer-=cnt[a[pos]^k];
27 }
28 
29 int main()
30 {
31     scanf("%d%d%d",&n,&m,&k);
32     bl = sqrt(n);
33     cnt[0] = 1;
34     for(int i = 1; i <= n; i++)
35     {
36         scanf("%d",&a[i]);
37         a[i] ^= a[i-1]; 
38     }
39     
40     for(int i = 1; i <= m; i++)
41     {
42         scanf("%d%d",&q[i].l,&q[i].r);
43         q[i].p = i;
44     }
45     
46     sort(q+1,q+1+m,cmp);
47     
48     for(int i = 1; i <= m; i++)
49     {
50         while(curL < q[i].l) remove(curL-1),curL++;
51         while(curL > q[i].l) curL--,add(curL-1);
52         while(curR < q[i].r) add(++curR);
53         while(curR > q[i].r) remove(curR--);
54         ans[q[i].p] = answer;
55     }
56     for(int i = 1; i <= m; i++)
57     printf("%d\n",ans[i]);
58     return 0;
59 }

 

转载于:https://www.cnblogs.com/MisakaAzusa/p/8909379.html

# P4363 [九省联考 2018] 一双木棋 chess ## 题目描述 菲菲和牛牛在一块 $n$ 行 $m$ 列的棋盘上下棋,菲菲执黑棋先手,牛牛执白棋后手。 棋局开始时,棋盘上没有任何棋子,两人轮流在格子上落子,直到填满棋盘时结束。 落子的规则是:一个格子可以落子当且仅当这个格子内没有棋子且这个格子的左侧及上方的所有格子内都有棋子。 棋盘的每个格子上,都写有两个非负整数,从上到下第 $i$ 行中从左到右第 $j$ 列的格子上的两个整数记作 $a_{i,j}$ 和 $b_{i,j}$。 在游戏结束后,菲菲和牛牛会分别计算自己的得分:菲菲的得分是所有有黑棋的格子上的 $a_{i,j}$ 之和,牛牛的得分是所有有白棋的格子上的 $b_{i,j}$ 的和。 菲菲和牛牛都希望,自己的得分减去对方的得分得到的结果最大。现在他们想知道,在给定的棋盘上,如果双方都采用最优策略且知道对方会采用最优策略,那么,最终的结果如何? ## 输入格式 第一行有两个整数,分别表示棋盘的行数 $n$ 和列数 $m$。 第 $2$ 到第 $(n + 1)$ 行,每行 $m$ 个整数,第 $(i + 1)$ 行的第 $j$ 个整数表示 $a_{i, j}$。 第 $(n + 2)$ 到第 $(2n + 1)$ 行,每行 $m$ 个整数,第 $(n + i + 1)$ 行的第 $j$ 个整数表示 $b_{i, j}$。 ## 输出格式 输出一行一个整数,表示菲菲的得分减去牛牛的得分的结果。 ## 输入输出样例 #1 ### 输入 #1 ``` 2 3 2 7 3 9 1 2 3 7 2 2 3 1 ``` ### 输出 #1 ``` 2 ``` ## 说明/提示 ### 样例 1 说明 ![](https://cdn.luogu.com.cn/upload/pic/16877.png) 棋盘如图所示,双方都采用最优策略时,棋局如下: - 菲菲下在第 $1$ 行第 $1$ 列(这是第一步时唯一可以落子的格子)。 - 牛牛下在第 $1$ 行第 $2$ 列。 - 菲菲下在第 $2$ 行第 $1$ 列。 - 牛牛下在第 $1$ 行第 $3$ 列。 - 菲菲下在第 $2$ 行第 $2$ 列。 - 牛牛下在第 $2$ 行第 $3$ 列(这是这一步时唯一可以落子的格子)。 - 填满棋盘,游戏结束。 盘面如下: ![](https://cdn.luogu.com.cn/upload/pic/16878.png) 菲菲的得分为 $2 + 9 + 1 = 12$,牛牛的得分为 $7 + 2 + 1 = 10$。 ### 数据规模与约定 各测试点信息如下表。 ![](https://cdn.luogu.com.cn/upload/pic/16879.png) - 对于编号为奇数的测试点,保证 $b_{i, j} = 0$。 - 对于全部的测试点,保证 $1 \leq n, m \leq 10$,$0 \leq a_{i, j}, b_{i, j} \leq 10^5$。 思路:先写m个0,然后看每一行,有几个棋子就在第几个0后面插入一个1。为什么WA了 ```cpp #include <iostream> using namespace std; const int INF = 0x3f3f3f3f; const int MAX_N = 15; int n, m, dp[1 << 20]; int a[MAX_N][MAX_N]; int b[MAX_N][MAX_N]; bool first(int s) { int f = 0; for (int j = 0, k = 0; k < n + m; k++) if (s >> k & 1) f ^= j; else j++; return (f & 1) ^ 1; } int main() { cin >> n >> m; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> a[i][j]; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> b[i][j]; for (int s = 1 << n; s <= (1 << n) - 1 << m - 1; s++) { if (__builtin_popcount(s) != n) continue; int f = first(s); dp[s] = f ? -INF : INF; bool flag = false; for (int i = 0, j = 0, k = 0; k < n + m; k++) if (s >> k & 1) { i++; if (flag) { int p = s ^ (1 << k) ^ (1 << k - 1); if (f) dp[s] = max(dp[s], dp[p] + a[i][j]); else dp[s] = min(dp[s], dp[p] - b[i][j]); flag = false; } } else j++, flag = true; } cout << dp[(1 << n) - 1 << m - 1] << &#39;\n&#39;; return 0; } ```
09-02
# P1563 [NOIP 2016 提高组] 玩具谜题 ## 题目背景 NOIP2016 提高组 D1T1 ## 题目描述 小南有一套可爱的玩具小人,它们各有不同的职业。 有一天,这些玩具小人把小南的眼镜藏了起来。小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外。如下图: ![](https://cdn.luogu.com.cn/upload/image_hosting/0u7em9pi.png) 这时 singer 告诉小南一个谜题:“眼镜藏在我左数第 $3$ 个玩具小人的右数第 $1$ 个玩具小人的左数第 $2$ 个玩具小人那里。” 小南发现,这个谜题中玩具小人的朝向非常关键,因为朝内和朝外的玩具小人的左右方向是相反的:面朝圈内的玩具小人,它的左边是顺时针方向,右边是逆时针方向;而面向圈外的玩具小人,它的左边是逆时针方向,右边是顺时针方向。 小南一边艰难地辨认着玩具小人,一边数着: singer 朝内,左数第 $3$ 个是 archer。 archer 朝外,右数第 $1$ 个是 thinker。 thinker 朝外,左数第 $2$ 个是 writer。 所以眼镜藏在 writer 这里! 虽然成功找回了眼镜,但小南并没有放心。如果下次有更多的玩具小人藏他的眼镜,或是谜题的长度更长,他可能就无法找到眼镜了。所以小南希望你写程序帮他解决类似的谜题。这样的谜題具体可以描述为: 有 $n$ 个玩具小人围成一圈,已知它们的职业和朝向。现在第 $1$ 个玩具小人告诉小南一个包含 $m$ 条指令的谜題,其中第 $z$ 条指令形如“向左数/右数第 $s$ 个玩具小人”。你需要输出依次数完这些指令后,到达的玩具小人的职业。 ## 输入格式 输入的第一行包含两个正整数 $n,m$,表示玩具小人的个数和指令的条数。 接下来 $n$ 行,每行包含一个整数和一个字符串,以逆时针为顺序给出每个玩具小人的朝向和职业。其中 $0$ 表示朝向圈内,$1$ 表示朝向圈外。保证不会出现其他的数。字符串长度不超过 $10$ 且仅由英文字母构成,字符串不为空,并且字符串两两不同。整数和字符串之间用一个空格隔开。 接下来 $m$ 行,其中第 $i$ 行包含两个整数 $a_i,s_i$,表示第 $i$ 条指令。若 $a_i=0$,表示向左数 $s_i$ 个人;若 $a_i=1$,表示向右数 $s_i$ 个人。 保证 $a_i$ 不会出现其他的数,$1 \le s_i < n$。 ## 输出格式 输出一个字符串,表示从第一个读入的小人开始,依次数完 $m$ 条指令后到达的小人的职业。 ## 输入输出样例 #1 ### 输入 #1 ``` 7 3 0 singer 0 reader 0 mengbier 1 thinker 1 archer 0 writer 1 mogician 0 3 1 1 0 2 ``` ### 输出 #1 ``` writer ``` ## 输入输出样例 #2 ### 输入 #2 ``` 10 10 1 C 0 r 0 P 1 d 1 e 1 m 1 t 1 y 1 u 0 V 1 7 1 1 1 4 0 5 0 3 0 1 1 6 1 2 0 8 0 4 ``` ### 输出 #2 ``` y ``` ## 说明/提示 **样例 1 说明** 这组数据就是【题目描述】中提到的例子。 **子任务** 子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解决一部分测试数据。 每个测试点的数据规模及特点如下表: ![](https://cdn.luogu.com.cn/upload/image_hosting/7su06u3r.png) 其中一些简写的列意义如下: - 全朝内:若为 $\surd$,表示该测试点保证所有的玩具小人都朝向圈内; - 全左数:若为 $\surd$,表示该测试点保证所有的指令都向左数,即对任意的 $1\leq z\leq m, a_i=0$; - $s=1$:若为 $\surd$,表示该测试点保证所有的指令都只数 $1$ 个,即对任意的 $1\leq z\leq m,s_i=1$; 职业长度为 $1$:若为 $\surd$,表示该测试点保证所有玩具小人的职业一定是一个长度为 $1$ 的字符串。 给出解题思路
03-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值