A dna
题目大意:给定一个长度为n,每项值为1或2的数列。有q次询问,对于每次询问回答一个区间[l,r],使得区间内的和等于xi。
时间限制:1000ms 空间限制:256mb
编译指令:开启O2和c++11
solution: 容易发现,若存在一个权值和为 x(x > 2)的串,必然存在一个权值和 为 x−2 的串。
证明:考虑其左右端点情况,如果存在一个是 T 直接将那个 T 抹掉即 可,否则两个就都是 A 将两个都抹掉即可。 分奇偶讨论预处理所有权值和的答案即可。
详细解答:
60分做法:
前缀和处理一下每两个端点之间的值,并对于每个可以组成的值预处理出答案O(1)回答
为了防止多次对同一可能数值处理,我们使用vis[]数组剪枝
代码如下
#include<bits/stdc++.h> using namespace std; const int Maxn = 1000010; struct st{ int be, ov; }nn[4 * Maxn]; int n, q; int pre [Maxn]; bool vis[4*Maxn]; int main () { freopen ( "dna.in" , "r" , stdin ); freopen ( "dna.out" , "w" , stdout ); scanf( " %d %d ", &n, &q ); pre[0] = 0; for ( int i = 1; i <= n; ++i ) { char ch ; ch = getchar(); if ( ch == 'T' ) pre[i] = pre[i - 1] + 2; if ( ch == 'A' ) pre[i] = pre[i - 1] + 1; } for ( int i = 0; i < n; ++i ) for ( int j = i + 1;j <= n; ++j ){ int ans = pre[j] - pre[i]; if( !vis[ans] ) { vis[ans] = true; nn[ans].be = i + 1; nn[ans].ov = j; } } while ( q-- ) { int x; scanf ( "%d", &x ); if( vis[x] ) printf ( "%d %d\n", nn[x].be, nn[x].ov ); else printf ("-1\n"); } return 0; }