P3514 [POI2011]LIZ-Lollipop(规律+瞎搞)

题意

给一个只有1和2的序列,每次询问有没有一个子串的和为x

( 1≤n,m≤1 000 000 )kkk ( 1≤k≤2 000 000 )

题解

我觉得是道好题。

主要是证明一个性质:假如有一个字串的和为偶(奇)数,那么小于这个偶(奇)数的所有偶(奇)数一定等于这个串的某个字串的和。

我们考虑这个串的边界l,r

假设l==1,r==1那么l++,r--,和可以减2

假设l==2,r==1那么l++,和可以减2;

假设l==1,r==2那么r--,和可以减2;

假设l==2,r==2那么l++或r--和可以减2;

所以我们找到可以用一个串表示的最大偶(奇)数然后一直缩小这个区间就行。

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=1000100;
 8 const int M=2000100;
 9 char s[M];
10 int n,m,a[N],sum,head,tail,l,r,ll[M],rl[M];
11 int main(){
12     scanf("%d%d",&n,&m);
13     cin>>s; 
14     int len=strlen(s);
15     for(int i=0;i<len;i++){
16         if(s[i]=='W')a[i+1]=1;
17         else a[i+1]=2;
18     }
19     for(int i=1;i<=n;i++)
20         sum+=a[i];
21     head=1;
22     tail=n;
23     while(a[head]!=1&&head<=n)head++;
24     head++;
25     while(a[tail]!=1&&tail>=1)tail--;
26     tail--;
27     l=1;r=n;
28     while(l<=r){
29     //    cout<<sum<<" "<<l<<" "<<r<<endl;
30         rl[sum]=r;ll[sum]=l;
31         if(a[l]==1&&a[r]==1){
32             l++;r--;sum-=2;
33         }
34         else if(a[l]==2){
35             l++;sum-=2;
36         }
37         else{
38             r--;
39             sum-=2;
40         }
41     }
42     sum=0;
43     if(head<=n||tail>=1){
44         if(head-1<n-tail){
45             l=head;
46             r=n;
47             for(int i=head;i<=n;i++)
48                 sum+=a[i];
49         }
50         else{
51             l=1;r=tail;
52             for(int i=1;i<=tail;i++)
53                 sum+=a[i];
54         }
55     //    cout<<sum<<endl;
56         while(l<=r){
57             rl[sum]=r;ll[sum]=l;
58             if(a[l]==1&&a[r]==1){
59                 l++;r--;sum-=2;
60             }
61             else if(a[l]==2){
62                 l++;sum-=2;
63             }
64             else{
65                 r--;
66                 sum-=2;
67             }
68         }
69     }
70     for(int i=1;i<=m;i++){
71         int k;
72         scanf("%d",&k);
73         if(ll[k]==0&&rl[k]==0)printf("NIE\n");
74         else printf("%d %d\n",ll[k],rl[k]);
75     }
76     return 0;
77 }

 

转载于:https://www.cnblogs.com/Xu-daxia/p/9447147.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值