【8.15校内测试】【队列】【manacher】

dp??不能确定转移状态。考虑用优先队列储存最优决策点,可是发现当前选择最优不能保证最后最优,在后面可以将之前用过的替换过来。

比如数据:

3 5

4 6

只储存a[i]来决策不能延展到后面的状态,因此每次选择过后把b[i]加入队列,下次选择最优时如果选择到了b[i],则表示用之前选择过的来替换到当前状态。

这里我开了两个优先队列。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 #define ll long long
 5 #define RG register
 6 using namespace std;
 7
 8 int n, a[100005], b[100005];
 9
10 priority_queue < int, vector < int > , greater < int > > q1, q2;
11
12 int main ( ) {
13     freopen ( "buy.in", "r", stdin );
14     freopen ( "buy.out", "w", stdout );
15     scanf ( "%d", &n );
16     for ( RG int i = 1; i <= n; i ++ )
17         scanf ( "%d", &a[i] );
18     for ( RG int i = 1; i <= n; i ++ )
19         scanf ( "%d", &b[i] );
20     ll ans = 0;
21     for ( RG int i = 1; i <= n; i ++ ) {
22         q1.push ( a[i] );
23         int r1 = 0, r2 = 0;
24         if ( !q1.empty ( ) ) {
25             int x = q1.top ( );
26             if ( b[i] > x ) r1 = b[i] - x;
27         }
28         if ( !q2.empty ( ) ) {
29             int x = q2.top ( );
30             if ( b[i] > x ) r2 = b[i] - x;
31         }
32         if ( r1 >= r2 && r1 ) ans += r1, q1.pop ( ), q2.push ( b[i] );
33         else if ( r2 > r1 && r2 ) ans += r2, q2.pop ( ), q2.push ( b[i] );
34     }
35     printf ( "%I64d", ans );
36     return 0;
37 }

记录前缀和,可以发现,从某一个点为起点时,向后延展出去的长度中一定有i到i+s这一段,所以用前缀和最大值建一棵线段树,每次查找i+s-1到i+e-1段的最大值,减去i-1的前缀和比较答案即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 using namespace std;
 5
 6 int n, s, e, a[100005];
 7 ll pre[100005], TR[400005];
 8
 9 void update ( int nd ) {
10     TR[nd] = max ( TR[nd << 1], TR[nd << 1 | 1] );
11 }
12
13 void build ( int nd, int l, int r ) {
14     if ( l == r ) {
15         TR[nd] = pre[l];
16         return ;
17     }
18     int mid = ( l + r ) >> 1;
19     build ( nd << 1, l, mid );
20     build ( nd << 1 | 1, mid + 1, r );
21     update ( nd );
22 }
23
24 ll query ( int nd, int l, int r, int L, int R ) {
25     if ( l >= L && r <= R ) return TR[nd];
26     int mid = ( l + r ) >> 1;
27     ll ans = -1e9;
28     if ( L <= mid ) ans = max ( ans, query ( nd << 1, l, mid, L, R ) );
29     if ( R > mid ) ans = max ( ans, query ( nd << 1 | 1, mid + 1, r, L, R ) );
30     return ans;
31 }
32
33 int main ( ) {
34     freopen ( "invest.in", "r", stdin );
35     freopen ( "invest.out", "w", stdout );
36     scanf ( "%d%d%d", &n, &s, &e );
37     for ( int i = 1; i <= n; i ++ ) {
38         scanf ( "%d", &a[i] );
39         pre[i] = pre[i-1] + a[i];
40     }
41     build ( 1, 1, n );
42     ll ans = 0;
43     for ( int i = 1; i <= n; i ++ ) {
44         if ( i + s - 1 > n ) break;
45         ll x = query ( 1, 1, n, i + s - 1, i + e - 1 );
46         ans = max ( x - pre[i-1], ans );
47     }
48     printf ( "%I64d", ans );
49     return 0;
50 }

关键时候manacher忘了怎么写!!先manacher一遍处理出以每个点为中心点的最长回文串长度,一定是奇数。开桶记录每个长度出现次数,从大到小枚举长度l,每次把l-2的次数加上l的次数,因为l的长度满足回文串l-2一定满足(同一中心点,注意k要开long long!

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 #define mod 19930726
 5 using namespace std;
 6
 7 ll max_r[2000005];
 8 int n;
 9 ll k;
10 ll ans = 1, flag[1000005];
11
12 char M[2000005], a[1000005];
13
14 inline ll min ( ll a, int b ) {
15     return a < b ? a : b;
16 }
17
18 ll mi ( ll a, ll b ) {
19     ll an = 1;
20     for ( ; b; b >>= 1, a = a * a % mod )
21         if ( b & 1 ) an = an * a % mod;
22     return an;
23 }
24
25 void manacher ( ) {
26     M[0] = ‘@‘;
27     for ( int i = 1; i <= n; i ++ ) {
28         M[2 * i - 1] = ‘#‘;
29         M[2 * i] = a[i];
30     }
31     M[2 * n + 1] = ‘#‘; M[2 * n + 2] = ‘$‘;
32     int center = 0; ll mx = 0;
33     int side = n * 2 + 1;
34     for ( int i = 1; i <= n * 2 + 1; i ++ ) {
35         if ( mx > i ) max_r[i] = min ( mx - (ll)i, max_r[center * 2 - i] );
36         else max_r[i] = 1;
37         while ( M[max_r[i]+i] == M[i-max_r[i]] ) max_r[i] ++;
38         if ( mx < i + max_r[i] ) {
39             mx = i + max_r[i]; center = i;
40         }
41     }
42 }
43
44 int main ( ) {
45     freopen ( "rehearse.in", "r", stdin );
46     freopen ( "rehearse.out", "w", stdout );
47     scanf ( "%d%I64d\n", &n, &k );
48     scanf ( "%s", a + 1 );
49     manacher ( );
50     ll MA = 0;
51     for ( int i = 1; i <= n; i ++ ) {
52         max_r[i*2] --;
53         flag[max_r[i*2]] ++;
54         MA = max ( MA, max_r[i*2] );
55     }
56     ll pos = MA;
57     while ( k > 0 ) {
58         ans = ( ans * mi ( pos, min ( flag[pos], k ) ) ) % mod;
59         flag[pos-2] += flag[pos];
60         k -= flag[pos];
61         pos = pos - 2;
62     }
63     printf ( "%I64d", ans );
64     return 0;
65 }

原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9484047.html

时间: 2024-08-29 23:44:06

【8.15校内测试】【队列】【manacher】的相关文章

第15章 进程间通行 15.6 XSI IPC 15.7 消息队列

15.6 XSI IPC (1)3种称作XSI IPC的IPC是: 1)消息队列 2)信号量 3)共享存储器 (2)标识符和键 1)标识符:是一个非负整数,用于引用IPC结构.是IPC对象的内部名. 2)键:IPC对象的外部名.可使多个合作进程能够在同一IPC对象上汇聚. (3)IPC_PRIVATE键: 用于创建一个新的IPC结构.不能指定此键来引用一个现有的IPC结构. (4)ftok函数: 由一个路径名和项目ID产生一个键. (5)ipc_perm结构体 规定了ipc结构的权限和所有者.

【8.16校内测试】【队列】【数学】【网络流/二分图最大匹配】

在一个队列中一次加入每一个字符,每次更新当前队列中的状态,当满足存在26个不同字符时,更新答案,删除队首. 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 #define RG register 6 using namespace std; 7 8 char s[2000005]; 9 int len, nex[2000005], flag[30]

【10.7校内测试】【队列滑窗】【2-sat】【贪心+栈二分+线段树(noip模拟好题)】【生日祭!】

比较好想的一道题,直接用队列滑窗,因为扫一遍往队列里加东西时,改变的只有一个值,开桶储存好就行了! #include<bits/stdc++.h> using namespace std; int n, k, r; inline int min(int a, int b) { return a > b ? b : a; } inline int max(int a, int b) { return a > b ? a : b; } int sum[200005], q[200005

【bzoj 1414】对称的正方形 单调队列+manacher

Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一个奇特的数,就是矩阵中上下对称且左右对称的正方形子矩阵的个数. Orez自然很想知道这个数是多少,可是矩阵太大,无法去数.只能请你编个程序来计算出这个数. Input 文件的第一行为两个整数n和m.接下来n行每行包含m个正整数,表示Orez得到的矩阵. Output 文件中仅包含一个整数answer

【8.31校内测试】【找规律二分】【DP】【背包+spfa】

打表出奇迹!表打出来发现了神奇的规律: 1 1 2 2 3 4 4 4 5 6 6 7 8 8 8 8 9 10 10 11 12 12 12 13 14 14 15 16 16 16 16 16... 嗯嗯嗯?没有规律?我们把每个数出现的次数列出来: 2 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 然后惊觉表中的数字是连续的,每个都至少有一个,而分解因数中有只要2的幂,有一个就会加一,比如8是2.4.8的倍数,在1的基础上会多三个.(1和2除外) 所以对于一个位置$x$,我们可

【10.5校内测试】【DP】【概率】

转移都很明显的一道DP题.按照不优化的思路,定义状态$dp[i][j][0/1]$表示吃到第$i$天,当前胃容量为$j$,前一天吃(1)或不吃(0)时能够得到的最大价值. 因为有一个两天不吃可以复原容量的定义,所以需要前一天的状态. 而注意,容量表示的是当前第$i$天吃之前的容量. 然后考虑压缩空间,将天数滚动.要注意的是滚动过后$now$指向的是$i$后一天的状态,因此刷表更新. #include<bits/stdc++.h> using namespace std; int n, m; i

【11.2晚校内测试】【装桶模拟】【单调栈】

真的是fo了,晚上还来一次测试...... mister[问题描述] 不久前 Mister 从太空中探测到一个奇怪的信号,他开始研究这个信号. 经过一些变换后,这个信号变成了长度为 n 的排列或者它的循环移位.对于进一步的研究 Mister 需要一些数据分析,这就是为什么他决定选择这个排列的循环移位,它有最小的可 能偏差.我们把排列的偏差定义为 求一个可能偏差最小的排列 p 的循环移位. 让我们表示 k(0≤k < n)的循环移位排列 p 的变化需要达到这种转变,例如: k = 0: 变成 p1

2019.6.28 校内测试 T1 Jelly的难题1

这题面有点难理解,建议直接跳到题意解释那一部分(虽然我觉得解释的不大对,但按照解释来做确实能AC): 按照“题意解释”的思路来思考这个题,那么就十分的简单了: 1.首先要读入这个字符矩阵,可以用cin(会不会TLE不知道),这里我用的是getchar读入: 2.从‘ * ’开始一遍广搜,记录一下每个‘ # ’被搜索到的时间,直到所有的点都被遍历过: 3.找出所有‘ # ’的位置时间最大的那个,就是第一问的答案,暂且记为much: 4.因为走过的格子每单位时间会增加1点高度,所以对于某一个格子 i

18清明校内测试T1

消失的数字(number) Time Limit:1000ms   Memory Limit:128MB 题目描述 rsy拥有n个数,这n个数分别是a1,a2,…,an. 后来出现了一个熊孩子zhw,用橡皮擦去了其中若干个数字,并且打乱了剩下的数字.rsy赶到现场后只剩下了m个数字b1,b2,…,bm,她想知道哪些数字被擦去了. 现在你需要告诉rsy被擦去的n-m个数是什么. 输入格式(number.in) 第一行一个数n,第二行n个数ai,表示一开始的数字. 第三行一个数m,第四行m个数bi,