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;
}

转载于:https://www.cnblogs.com/LLppdd/p/9175966.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值