bzoj2217 [Poi2011]Lollipop
[Poi2011]Lollipop
Time Limit: 15 Sec Memory Limit: 64 MBSec Special Judge
Description
有一个长度为n的序列a1,a2,...,an。其中ai要么是1("W"),要么是2("T")。
现在有m个询问,每个询问是询问有没有一个连续的子序列,满足其和为q。
Input
第一行n,m (1<=n,m<=1000000)
第二行这个序列,起始编号为1,终止编号为n
下面每行一个询问q,询问有没有一个连续的子序列,满足其和为q (1<=q<=2000000)
Output
对于每个询问,输出一行,如果有,输出这个序列的起点和终点(如果有多个输出任意一个);如果没有,输出“NIE”。
Sample Input
5 3
TWTWT
5
1
7
Sample Output
1 3
2 2
NIE
大概就是有一些想法,比如如果一个奇数能被凑出来,那么比这个奇数小的奇数也一定能够凑出来。。。。偶数同理。 然后呢还有一个就是任何一个区间都可以从【1,x】这个区间整体平移几位凑出来。再进一步说,如果说你要凑t,那么要么有一个【1,x】直接满足,要么有一个【1,x】为t+1 然后呢你就开始平移,直到左边减去的一个和右边加的一个一个1一个2就凑出来了。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 6;
struct ld{
int data, tw;
}num[maxn];
char s[maxn];
int n, m, x, lpd, sum1, sum2, f[maxn * 2], lll[maxn * 2], rrr[maxn * 2];
inline void putit()
{
scanf("%d%d", &n, &m); scanf("%s", s + 1);
for(int i = 1; i <= n; ++i){
if(s[i] == 'W') num[i].data = 1;
if(s[i] == 'T') num[i].data = 2;
}
for(int i = n; i >= 1; --i){
num[i].tw = num[i + 1].tw + 1;
if(s[i] == 'W') num[i].tw = 0;
}
}
void workk()
{
int sum = 0;
for(int i = 1; i <= n; ++i){
sum += num[i].data;
if(s[i]=='T')
{
if(num[1].tw < num[i].tw)
lll[sum - 1] = num[1].tw + 2, rrr[sum - 1] = i + num[1].tw;
else if(i + num[i].tw != n + 1)
lll[sum - 1] = 1 + num[i].tw, rrr[sum - 1] = i + num[i].tw;
}
}
}
inline void prepare()
{
int lin = 0;
for(int i = 1; i <= n; ++i){
lin += num[i].data;
f[lin] = i;
lll[lin] = 1; rrr[lin] = i;
}
sum1 = lin;
int lin1 = sum1, lin2 = sum1;
for(int i = 1; i <= n; ++i){
lin1 -= num[i].data;
if(num[i].data == 1) break;
}
for(int i = n; i >= 1; --i){
lin2 -= num[i].data;
if(num[i].data == 1) break;
}
sum2 = max(lin1, lin2);
}
int main()
{
//freopen("data.in", "r", stdin);
//freopen("lpl.out", "w", stdout);
putit();
prepare();
workk();
for(int i = 1; i <= m; ++i){
scanf("%d", &x);
if(lll[x] == 0) puts("NIE");
else printf("%d %d\n", lll[x], rrr[x]);
}
return 0;
}
心如花木,向阳而生。