Codeforces Ilya and Queries
递推(DP)
http://codeforces.com/contest/313/problem/B
题意:比较好懂,一个字符串只有.或者#字符,给你一段区间[x,y],其实y>x,让你在这个区间里面统计一个数字,即这个子串,相邻两位,若s[i]=s[i+1]则计数一次,然后输出结果
这题一看,其实想到了线段树,因为原串,如果一段连续的.....则看成是一串白色的段,一段连续的#####则看成是一段黑色的段,那么原串可以看成是线段树的总区间被一系列的黑白段覆盖,对于每个查询就在线段树上查询它被什么黑白段覆盖,并且覆盖了多长,不过鉴于比赛时间短,而且好像大材小用的感觉,就没再往线段树上面想,比赛后看到这题真被归为数据结构,男单真的是线段树?或者其他的?
不过正解觉得应该是用递推水过,dp[i]表示从1到i,有多少个相邻的s[x] = s[x+1]
递推方程很好写
dp[1] = 0
if s[i] = s[i-1] dp[i] = dp[i-1] + 1
else dp[i] = dp[i-1]
对于一个查询[x,y],则一步可以查到,即dp[y] - dp[x]
但是还要处理一下接口处,如果s[x] = s[x-1],那么还要减掉1
不难看代码,我再想想怎么用数据结构写
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define N 100010 int dp[N],n; char s[N]; int main() { scanf("%s",s+1); n = strlen(s+1); dp[0] = dp[1] = 0; for(int i=2; i<=n; i++) dp[i] = (s[i] == s[i-1]) ? dp[i-1]+1 : dp[i-1]; int q; scanf("%d",&q); while(q--) { int x,y; scanf("%d%d",&x,&y); int res = dp[y] - dp[x-1]; if(x!=1 && s[x] == s[x-1]) res--; printf("%d\n",res); } return 0; }