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 }