[关闭]
@ysner 2018-10-08T13:36:43.000000Z 字数 1217 阅读 1704

[POI2011]LIZ-Lollipop

构造 思维


题面

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

解析

一道挺不错的思维题。

只有的性质其实很妙。这意味着大多数的都是存在的。
先预处理前缀和。
如果当前不是某一前缀和,那么一定是某一前缀和。(因为不为前缀和当且仅当)
那么我们可以利用一下前缀和为的区间来得到所求区间。

显然我们需要在左端或右端删掉一个
可以预处理一下每个点右边最近的在哪里。
然后两边跳同样的距离即可(让一边删掉一个,另一边没删)。
注意一下边界(比如尽量内缩而不是外伸),问题就解决了。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;++i)
  11. #define fq(i,a,b) for(re int i=a;i>=b;--i)
  12. using namespace std;
  13. const int N=2e6+100;
  14. int las[N],n,m,a[N],pos[N];
  15. char s[N];
  16. il ll gi()
  17. {
  18. re ll x=0,t=1;
  19. re char ch=getchar();
  20. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  21. if(ch=='-') t=-1,ch=getchar();
  22. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  23. return x*t;
  24. }
  25. int main()
  26. {
  27. n=gi();m=gi();
  28. scanf("%s",s+1);
  29. fp(i,1,n) a[i]=a[i-1]+(s[i]=='W'?1:2),pos[a[i]]=i;
  30. fq(i,n,1) if(s[i]=='T') las[i]=las[i+1]+1;
  31. while(m--)
  32. {
  33. re int x=gi();
  34. if(x>a[n]) puts("NIE");
  35. else if(pos[x]) printf("%d %d\n",1,pos[x]);//x+1一定存在
  36. else if(las[pos[x+1]]>las[1]) printf("%d %d\n",2+las[1],pos[x+1]+las[1]);//前面删1(记得是1~1+las[1]删了,所以从1+las[1]+1开始)
  37. else if(las[pos[x+1]]+pos[x+1]<=n) printf("%d %d\n",1+las[pos[x+1]],pos[x+1]+las[pos[x+1]]);//后面删1
  38. else puts("NIE");
  39. }
  40. return 0;
  41. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注