JZOJ #4708 / CODEFORCES #217 E.Alien DNA

题目描述:

这题改编自CF217E,给出一串字符串,有n个操作,将区间[l, r]的字符中编号为奇数的写下,再把偶数的写在后面,然后把它们插入r和r + 1之间,问最后字符串的前k位。

解题思路:

因为前面的操作不会对后面的操作有影响,所以我们考虑把操作倒过来做。相应的,一开始就只有k个位置有效,然后对于操作[l, r],就把[r + 1, r + (r - l + 1)]标记为已操作,并记录每一位是哪一位转移过来的。然后对于前一个操作,就只能做那些未标记的位置。相当于对未标记的位置重标号,然后像刚刚一样继续做。当然,如果操作位置超出了当前未标记的位置,就不用做了。所以这样最多只要做k次。具体要怎么记录位置呢,可以用线段树,类似二分的找。在oj上被卡了线段树做法,所以改成非递归版卡过去了。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 const int N = 3e6 + 10;
 7 int k, n, l[N], r[N], tr[N * 4], f[N];
 8 char s[N], ans[N];
 9
10 void build(int o, int l, int r) {
11     tr[o] = r - l + 1;
12     if (l == r) return;
13     int m = l + r >> 1;
14     build(o << 1, l, m);
15     build(o << 1 | 1, m + 1, r);
16 }
17
18 int find(int o, int l, int r, int k, int p) {
19     while (l != r) {
20         tr[o] -= p;
21         int m = l + r >> 1;
22         if (tr[o << 1] >= k) r = m, o <<= 1;
23         else k -= tr[o << 1], o = o << 1 | 1, l = m + 1;
24     }
25     tr[o] -= p;
26     return l;
27 }
28
29 void work() {
30     for (int i = n; i >= 1; i --) {
31         if (r[i] >= tr[1]) continue;
32         int t = l[i] & 1 ^ 1;
33         int now = l[i] + t;
34         if (now > r[i]) now = l[i] + (t ^ 1);
35         for (int j = 1; j <= r[i] - l[i] + 1 && r[i] < tr[1]; j ++) {
36             int p = find(1, 1, k, r[i] + 1, 1);
37             f[p] = find(1, 1, k, now, 0);
38             now += 2;
39             if (now > r[i]) now = l[i] + (t ^ 1);
40         }
41     }
42     for (int i = 1, j = 1; i <= k; i ++)
43         if (f[i]) ans[i] = ans[f[i]]; else ans[i] = s[j ++];
44     puts(ans + 1);
45 }
46
47 int main() {
48     gets(s + 1);
49     scanf("%d %d", &k, &n);
50     build(1, 1, k);
51     for (int i = 1; i <= n; i ++) scanf("%d %d", &l[i], &r[i]);
52     work();
53     return 0;
54 }
时间: 2024-10-10 20:30:42

JZOJ #4708 / CODEFORCES #217 E.Alien DNA的相关文章

JZOJ #4707 / CODEFORCES #704 B.Ant Man

题目描述: 这题改编自cf704b,在数轴上有n个点,从一个点跳到另一个点的收益是两点的距离和给出的数组对应下标的值,并且往左和往右的数组不同.要求从一个点起跳,经过每个点刚好一次,最后回到原点,使得收益最大. 解题思路: 因为每个点的贡献只跟跳过来的方向有关,与哪个点跳过来无关.所以可以考虑dp,因为最好是一个环,所以每个点的出度和入度都是一.设f[i][j][k]表示前i个点还有j个点的出边未匹配,k个点的入边未匹配.考虑i+1个点,有四种情况,左进左出,右进右出,左进右出,右进左出,相应的

Codeforces Gym 100610 Problem A. Alien Communication Masterclass 构造

Problem A. Alien Communication Masterclass Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100610 Description Andrea is a famous science fiction writer, who runs masterclasses for her beloved readers. The most popular one is the

CodeForces 520C DNA Alignment

题意: 一段DNA序列(10^5长度)  定义h函数为两序列相同碱基个数  p函数为分别移动两个DNA序列后所有可能的h函数之和  问使p最大的序列有多少个 思路: 根据p函数的定义  我们发现p这个函数其实就是A序列每个碱基和B序列每个碱基比较再乘一个n 因此可以贪心构造B序列  即每次新加一个碱基必定是A序列中出现次数最多的碱基 那么最后的答案就是A序列中出现次数最多的碱基种类数的n次方 代码: #include<cstdio> #include<iostream> #incl

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) E DNA Evolution

DNA Evolution 题目让我们联想到树状数组或者线段树,但是如果像普通那样子统计一段的和,空间会爆炸. 所以我们想怎样可以表示一段区间的字符串. 学习一发大佬的解法. 开一个C[10][10][4][n],就可以啦,第二维表示e的长度,第一维表示i%e的长度,第三维表示颜色,第四维求和了. 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5+5; 4 char s[maxn]; 5 map&l

C. DNA Alignment 数学公式推导 Codeforces Round #295 (Div. 2)

C. DNA Alignment time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output Vasya became interested in bioinformatics. He's going to write an article about similar cyclic DNA sequences, so he invente

Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) E. DNA Evolution 树状数组

E. DNA Evolution time limit per test 2 seconds memory limit per test 512 megabytes input standard input output standard output Everyone knows that DNA strands consist of nucleotides. There are four types of nucleotides: "A", "T", "

Codeforces 521A DNA Alignment 规律

题目链接:点击打开链接 题意: 给定长度为n的一个字符串s. 构造长度也为n的字符串t.使得p(s,t)值最大,问有多少个不同的t h(s,t) = 对应位置上字母相同的个数 ρ("AGC",?"CGT")?=? h("AGC",?"CGT")?+?h("AGC",?"GTC")?+?h("AGC",?"TCG")?+? h("GCA&q

Codeforces Round #295 Div1 A(DNA Alignment)

Problem Limits TimeLimit(ms):2000 MemoryLimit(MB):256 n∈[1,105] 字符集∈[A,G,C,T] Look up Original Problem From here Solution 设Ni表示s串中A,G,C,T出现的次数,Mi表示t串中A,G,C,T出现的次数,则max=∑4i=1Ni×Mi,Ni越大,对max的贡献越大,应当分配的Mi越多. answer=an,由推公式得知. 当a=1时,answer=1: 当a=2时,answe

Codeforces #295(Div 2) A Pangram、B Two Buttons、C DNA Alignment

A #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <map> #include <set> #include <vector> using namespace std; int A[50]; int main() { int n; string s; cin>>n; cin>&g