1.Trie(字典树、前缀树)
题目:http://hihocoder.com/problemset/problem/1014
题意:开始给定一些字符串,求每次以询问的字符串为前缀的字符串个数
思路:Trie
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1000005;
const int C_size = 26;
struct Trie{
int trieN;
int ch[N][C_size], val[N];
void init(){
memset(ch[0],0,sizeof(ch[0]));
trieN = -1;
newnode();
}
int newnode(){
memset(ch[++trieN], 0, sizeof(ch[0]));
val[trieN] = 0;//fail[trieN] = 0;
return trieN;
}
void insert(char *str){
int cur = 0;
for(int i = 0;str[i] != '\0';i++){
int d = str[i] - 'a';
if(!ch[cur][d])
ch[cur][d] = newnode();
cur = ch[cur][d];
val[cur]++;
}
}
int query(char *str){
int cur = 0;
for (int i = 0;str[i] != '\0';i++){
int d = str[i] - 'a';
if(ch[cur][d])
cur = ch[cur][d];
else//ÎÞ·¨Æ¥Åä
return 0;
}
return val[cur];
}
}trie;
int main(){
int n,m;
char str[15];
while(~scanf("%d",&n)){
trie.init();
for(int i = 0;i < n;i++){
scanf("%s",str);
trie.insert(str);
}
scanf("%d",&m);
while(m--){
scanf("%s",str);
printf("%d\n",trie.query(str));
}
}
return 0;
}
题目:http://acm.split.hdu.edu.cn/showproblem.php?pid=5687
题意:对字符串的简单插入、删除、查询
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 3000005;
const int C_size = 26;
struct Trie{
int trieN;
int ch[N][C_size], val[N];
void init(){
memset(ch[0],0,sizeof(ch[0]));
trieN = -1;
newnode();
}
int newnode(){
memset(ch[++trieN], 0, sizeof(ch[0]));
val[trieN] = 0;//fail[trieN] = 0;
return trieN;
}
void insert(char *str){
int cur = 0;
for(int i = 0;str[i] != '\0';i++){
int d = str[i] - 'a';
if(!ch[cur][d])
ch[cur][d] = newnode();
cur = ch[cur][d];
val[cur]++;
}
}
void del(char *str){
int cur = 0;
for(int i = 0;str[i] != '\0';i++){
int d = str[i] - 'a';
if(!ch[cur][d])
return;
cur = ch[cur][d];
}
int x = 0;
for(int i = 0;str[i] != '\0';i++){
int d = str[i] - 'a';
if(!ch[x][d])
return;
int pre = x;
x = ch[x][d];
val[x] -= val[cur];
if(val[x] == 0)
ch[pre][d] = 0;
}
}
int query(char *str){
int cur = 0;
for (int i = 0;str[i] != '\0';i++){
int d = str[i] - 'a';
if(ch[cur][d])
cur = ch[cur][d];
else//ÎÞ·¨Æ¥Åä
return 0;
}
return val[cur];
}
}trie;
int main(){
int n;
char str[35],type[10];
scanf("%d",&n);
trie.init();
for(int i = 0;i < n;i++){
scanf("%s %s",type,str);
if(type[0] == 'i')
trie.insert(str);
else if(type[0] == 'd')
trie.del(str);
else{
if(trie.query(str))
puts("Yes");
else
puts("No");
}
}
return 0;
}
题目:http://codeforces.com/contest/706/problem/D
题意:给你一个集合,对集合操作,“+”代表加入一个数,“-代表”删除一个数,“?”代表查询x与集合中任意数xor的最大值
思路:将每个数拆成二进制的形式插入Trie树中,按照字符串的操作来即可
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 4000005;
int a[N][4],sum[N];
int sz;
void Init()
{
memset(a,0,sizeof(a));
memset(sum,0,sizeof(sum));
sz = 1;
}
void Insert(int x)
{
int num[35];
memset(num,0,sizeof(num));
int cnt = 0;
while(x)
{
num[cnt++] = x % 2;
x /= 2;
}
int u = 0,n = 34;
for(int i = n;i >= 0;i--)
{
if(!a[u][num[i]])
a[u][num[i]] = sz++;
u = a[u][num[i]];
sum[u]++;
}
}
void Delete(int x)
{
int num[35];
memset(num,0,sizeof(num));
int cnt = 0;
while(x)
{
num[cnt++] = x % 2;
x /= 2;
}
int u = 0,n = 34;
for(int i = n;i >= 0;i--)
{
int v = a[u][num[i]];
sum[v]--;
if(!sum[v])
a[u][num[i]] = 0;
u = v;
}
}
int Query(int y)
{
int num[35];
memset(num,0,sizeof(num));
int cnt = 0;
while(y)
{
num[cnt++] = y % 2;
y /= 2;
}
for(int i = 0;i <= 34;i++)
num[i]= num[i] ? 0 : 1;
int u = 0,n = 34,v,w;
int ans = 0;
for(int i = n;i >= 0;i--)
{
if(num[i])
{
v = 1;
w = 0;
}
else
{
w = 1;
v = 0;
}
if(a[u][v])
{
u = a[u][v];
ans += 1 << i;
}
else
{
u = a[u][w];
//if(!v)
//ans += 1 << i;
}
}
return ans;
}
int main()
{
int t,x;
cin >> t;
char s[20];
Init();
Insert(0);
for(int ca = 1;ca <= t;ca++)
{
scanf("%s%d",s,&x);
if(s[0] == '+')
Insert(x);
else if(s[0] == '-')
Delete(x);
else
printf("%d\n",Query(x));
}
return 0;
}
题目:LA-3942
题意:给你一个T串,然后输入n个P串,让你求将T串分解成若干个P串的方案数
思路:dp+Trie
dp[i]代表从i开始的字符串分解方案数,所以状态转移方程为dp[i] = (dp[i] + dp[i + len[P])
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 400005;
const int C_size = 26;
const int MOD = 20071027;
vector<int> ans;
int len[N],dp[N];
struct Trie{
int trieN;
int ch[N][C_size], val[N];
void init(){
memset(ch[0],0,sizeof(ch[0]));
trieN = -1;
newnode();
}
int newnode(){
memset(ch[++trieN], 0, sizeof(ch[0]));
val[trieN] = 0;//fail[trieN] = 0;
return trieN;
}
void insert(char *str,int index){
int cur = 0;
for(int i = 0;str[i] != '\0';i++){
int d = str[i] - 'a';
if(!ch[cur][d])
ch[cur][d] = newnode();
cur = ch[cur][d];
}
val[cur] = index;//×Ö·û´®±àºÅ
}
void query(char *str,int len){
int cur = 0;
for (int i = 0;i < len;i++){
int d = str[i] - 'a';
if(!ch[cur][d])
return;
cur = ch[cur][d];
if(val[cur]) ans.push_back(val[cur]);
}
//return val[cur];
}
}trie;
char str[300005],s[4005];
int main(){
int n,ca = 0;
while(~scanf("%s",&str)){
scanf("%d",&n);
trie.init();
for(int i = 1;i <= n;i++){
scanf("%s",s);
len[i] = strlen(s);
trie.insert(s,i);
}
memset(dp,0,sizeof(dp));
int ls = strlen(str);
dp[ls] = 1;
for(int i = ls-1;i >= 0;i--)
{
ans.clear();
trie.query(str+i,ls-i);
for(int j = 0;j < ans.size();j++)
dp[i] = (dp[i] + dp[i + len[ans[j]]]) % MOD;
}
printf("Case %d: %d\n",++ca,dp[0]);
}
return 0;
}
2.KMP
见http://blog.csdn.net/huatian5/article/details/51307735
3.Aho-Corasick自动机(AC自动机)
题目:http://acm.split.hdu.edu.cn/showproblem.php?pid=2222
题意:给你n个P串,再给你一个T串,让求T中有多少P串
思路:AC自动机
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
const int C_size = 26;
char str[N];
struct Trie{
const static int maxn = N;
const static int type = C_size;
int ch[maxn][type],fail[maxn],val[maxn];
int root,L;
int newnode(){
for(int i = 0;i < type;i++)
ch[L][i] = -1;
val[L++] = 0;
return L-1;
}
void init(){
L = 0;
root = newnode();
}
void insert(char* str){
int len = strlen(str);
int now = root;
for(int i = 0;str[i];i++){
int id=str[i]-'a';
if(ch[now][id] == -1)
ch[now][id] = newnode();
now=ch[now][id];
}
val[now]++;
}
void build(){
queue<int>Q;
fail[root] = root;
for(int i = 0;i < type;i++)
if(ch[root][i] == -1)
ch[root][i] = root;
else{
fail[ch[root][i]] = root;
Q.push(ch[root][i]);
}
while(!Q.empty()){
int now = Q.front();Q.pop();
for(int i = 0;i < type;i++)
if(ch[now][i] == -1)
ch[now][i] = ch[fail[now]][i];
else{
fail[ch[now][i]] = ch[fail[now]][i];
Q.push(ch[now][i]);
}
}
}
int query(char *str){
int ans = 0;
int now = root;
for(int i = 0;str[i];i++){
now = ch[now][str[i]-'a'];
int tmp = now;
while(tmp != root){
ans += val[tmp];
val[tmp] = 0;
tmp = fail[tmp];
}
}
return ans;
}
}AC;
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
AC.init();
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%s",str);
AC.insert(str);
}
AC.build();
getchar();
gets(str);
printf("%d\n",AC.query(str));
}
return 0;
}
题目:http://acm.split.hdu.edu.cn/showproblem.php?pid=5880
题意:给你n个P串,再给你一个T串,让你将T串中的P串改为“*”
思路:AC自动机,匹配到P串后,在串尾标记下len,输出的时候判断下len就行了
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
const int C_size = 26;
char str[N];
int pos[N];
struct Trie{
const static int maxn = N;
const static int type = C_size;
int ch[maxn][type],fail[maxn],val[maxn],l[maxn];
int root,L;
int newnode(){
for(int i = 0;i < type;i++)
ch[L][i] = -1;
l[L] = 0;
val[L++] = -1;
return L-1;
}
void init(){
L = 0;
root = newnode();
}
void insert(char* str){
int len = strlen(str);
int now = root;
for(int i = 0;str[i];i++){
int id=str[i]-'a';
if(ch[now][id] == -1)
ch[now][id] = newnode();
now=ch[now][id];
}
val[now]=1;
l[now]=len;
}
void build(){
queue<int>Q;
fail[root] = root;
for(int i = 0;i < type;i++)
if(ch[root][i] == -1)
ch[root][i] = root;
else{
fail[ch[root][i]] = root;
Q.push(ch[root][i]);
}
while(!Q.empty()){
int now = Q.front();
Q.pop();
for(int i = 0;i < type;i++)
if(ch[now][i] == -1)
ch[now][i] = ch[fail[now]][i];
else{
fail[ch[now][i]] = ch[fail[now]][i];
Q.push(ch[now][i]);
}
}
}
void solve(char* str){
int id;
int len = strlen(str);
int now = root;
memset(pos,0,sizeof(pos));
for(int i = 0;i < len;i++){
if(str[i]>='A'&&str[i]<='Z') id=str[i]-'A';
else if(str[i]>='a'&&str[i]<='z') id=str[i]-'a';
else continue;
now = ch[now][id];
int temp=now;
while(temp != root){
if(val[temp] != -1){
pos[i+1] -= 1;
pos[i-l[temp]+1] += 1;
break;
}
temp = fail[temp];
}
}
long long cnt = 0;
for(int i=0;i<len;i++){
cnt += pos[i];
if(cnt <= 0)
printf("%c",str[i]);
else
printf("*");
}
printf("\n");
}
}AC;
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
AC.init();
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%s",str);
AC.insert(str);
}
AC.build();
getchar();
gets(str);
AC.solve(str);
}
return 0;
}
题目:http://acm.split.hdu.edu.cn/showproblem.php?pid=6208
题意:给你n个串,让找出最长的一个串,包含其余n-1个串,没有输出No
思路:用AC自动机 找出最长的串,看是否其余n-1个串都能匹配到
代码(来自某好心人):
#include<bits/stdc++.h>
using namespace std;
const int N = 100005;
const int M = 26;
queue<int> q;
vector<string> vec;
bool vis[N];
struct Trie{
int trieN;
int ch[N][M], val[N], fail[N];
void init() {
memset(vis,0,sizeof(vis));
trieN = -1;
newnode();
}
int newnode() {
memset(ch[++trieN], 0, sizeof(ch[0]));
val[trieN] = fail[trieN] = 0;
return trieN;
}
void insert(const string &str, int index) {
int cur = 0;
for (int i = 0;str[i];i++) {
int d = str[i] - 'a';
if (!ch[cur][d])
ch[cur][d] = newnode();
cur = ch[cur][d];
}
if (val[cur]) vis[index] = 1;
else val[cur] = index;
}
void build() {
for (int i = 0;i < M;i++) {
if (ch[0][i])
q.push(ch[0][i]);
}
while (!q.empty()) {
int cur = q.front(); q.pop();
for (int i = 0;i < M;i++) {
int &next = ch[cur][i];
if (next) {
fail[next] = ch[fail[cur]][i];
q.push(next);
}
else next = ch[fail[cur]][i];
}
}
}
void query(const string &str) {
int cur = 0, tmp;
for (int i = 0;str[i];i++) {
int d = str[i] - 'a';
tmp = cur = ch[cur][d];
while (tmp && ~val[tmp]) {
if (val[tmp] != -1) vis[val[tmp]] = 1;
val[tmp] = -1;
tmp = fail[tmp];
}
}
}
}ac;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--){
ac.init();
int n;
cin >> n;
vec.resize(n+1);
int maxlen = 0,maxi;
for(int i = 1;i <= n;i++){
cin >> vec[i];
if (vec[i].size() > maxlen){
maxlen = vec[i].size();
maxi = i;
}
}
vis[maxi] = 1;
for(int i = 1;i <= n;i++){
if (i != maxi)
ac.insert(vec[i],i);
}
ac.build();
ac.query(vec[maxi]);
bool flag = 1;
for(int i = 1;i <= n && flag;i++){
if (!vis[i]) flag = 0;
}
if(flag) cout << vec[maxi] << '\n';
else cout << "No\n";
}
return 0;
}
4.后缀数组(SA)
- Suffix[i] :Str下标为i ~ Len的连续子串(即后缀)
- Rank[i] : Suffix[i]在所有后缀中的排名
- sa : 满足Suffix[sa1] < Suffix[sa2] …… < Suffix[sa[Len]],即排名为i的后缀为Suffix[sa[i]] (与Rank是互逆运算)
- height[i] : 表示Suffix[sa[i]]和Suffix[sa[i - 1]]的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀
题目:poj2774
题意:给你两个子串,让你求最长公共子串的长度
思路:将两个字符串连接(中间加一个非字母的分隔符号),然后保证两个后缀分别在两个串中,即sa[i-1]>=0 && sa[i-1]<len1 && sa[i]>=len1 || sa[i]>=0 && sa[i]<len1 && sa[i-1]>=len1
然后结果就是最大的height[i]
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int Max = 200005;
int wa[Max],wb[Max],wsf[Max],wv[Max],sa[Max];
int Rank[Max],height[Max],s[Max];
char str1[Max],str2[Max];
int cmp(int *r,int a,int b,int k)
{
return r[a]==r[b]&&r[a+k]==r[b+k];
}
//±¶ÔöO(nlogn)
void getsa(int *r,int *sa,int n,int m)
{
int i, j, p, *x = wa, *y = wb;
for (i = 0; i < m; ++i) wsf[i] = 0;
for (i = 0; i < n; ++i) wsf[x[i]=r[i]]++;
for (i = 1; i < m; ++i) wsf[i] += wsf[i-1];
for (i = n-1; i >= 0; --i) sa[--wsf[x[i]]] = i;
for (j = 1, p = 1; p < n; j *= 2, m = p)
{
for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = 0; i < n; ++i) wv[i] = x[y[i]];
for (i = 0; i < m; ++i) wsf[i] = 0;
for (i = 0; i < n; ++i) wsf[wv[i]]++;
for (i = 1; i < m; ++i) wsf[i] += wsf[i-1];
for (i = n-1; i >= 0; --i) sa[--wsf[wv[i]]] = y[i];
for (swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
}
}
void calheight(int r[], int n)
{
int i, j, k = 0;
for (i = 1; i <= n; ++i) Rank[sa[i]] = i;
for (i = 0; i < n; height[Rank[i++]] = k)
for (k?k--:0, j = sa[Rank[i]-1]; r[i+k] == r[j+k]; k++);
}
int main()
{
char str1[Max],str[Max];
while(~scanf("%s",str1))
{
scanf("%s",str2);
int len1=strlen(str1),len2=strlen(str2);
int num=0;
for(int i=0;i<len1;i++)
s[num++]=str1[i]-'a'+1;
s[num++]=28;
for(int i=0;i<len2;i++)
s[num++]=str2[i]-'a'+1;
s[num]=0;
getsa(s,sa,num+1,30);
calheight(s,num);
int ans=0;
for(int i=2;i<num;i++)
{
if(height[i]>ans)
{aaaa aaaa
if(sa[i-1]>=0 && sa[i-1]<len1 && sa[i]>=len1)
ans = max(ans,height[i]);
if(sa[i]>=0 && sa[i]<len1 && sa[i-1]>=len1)
ans = max(ans,height[i]);
}
}
printf("%d\n",ans);
}
return 0;
}
题目:Problem I 失恋的小T
题意:问一个字符串里面不同的子串有有多少
思路:我们知道所有子串的个数,只需要找到相同的子串个数,减掉重复的就行了。对于每个后缀来说,贡献为len-sa[i](sa[i]保存的排名为i的后缀开头位置)。
height[i] 就是排名相邻的两个后缀的最长公共前缀,我们找出最长前缀也就是重复的一部分子串,例如aaaabab,abab和ab的最长公共前缀为ab,重复子串有a、ab,所以每个后缀的贡献为贡献为len-sa[i]-height[i]
代码:
#include <bits/stdc++.h>
using namespace std;
const int Max = 200005;
int wa[Max],wb[Max],wsf[Max],wv[Max],sa[Max];
int ra[Max],height[Max],s[Max];
char str[Max];
int cmp(char *r,int a,int b,int k)
{
return r[a]==r[b]&&r[a+k]==r[b+k];
}
//倍增O(nlogn)
void getsa(char *r,int *sa,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) wsf[i]=0;
for(i=0;i<n;i++) wsf[x[i]=r[i]]++;
for(i=1;i<m;i++) wsf[i]+=wsf[i-1];
for(i=n-1;i>=0;i--) sa[--wsf[x[i]]]=i;
/***********************************/
for(p=1,j=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) wsf[i]=0;
for(i=0;i<n;i++) wsf[wv[i]]++;
for(i=1;i<m;i++) wsf[i]+=wsf[i-1];
for(i=n-1;i>=0;i--) sa[--wsf[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
}
return;
}
void getheight(char *r,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) ra[sa[i]]=i;
for(i=0;i<n;i++)
{
if(k)
k--;
else
k=0;
j=sa[ra[i]-1];
while(r[i+k]==r[j+k])
k++;
height[ra[i]]=k;
}
}
int main()
{
while(~scanf("%s",str))
{
int len = strlen(str);
getsa(str,sa,len+1,130);
getheight(str,len);
int res = 0;
for(int i = 1;i <= len;i++)
res += len - sa[i] - height[i];
printf("%d\n",res);
}
}
题目:http://acm.split.hdu.edu.cn/showproblem.php?pid=6194
题意:给你一个字符串,让求出现k次的子串个数
思路:我们枚举每个sa[i](长度k),suffix[ i~i+k-1 ]的的lcp(min{height[i]}),假设为s(长度为len),那么有len个子串至少出现了k次,因为题目要求是出现k次,然后我们要减去至少出现了k+1次的子串,即suffix[ i-1~i+k-1]和suffix[ i~i+k]的lcp,容斥加上suffix[ i-1~i+k]的lcp
求height[]的最小值用rmq处理
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Max = 200005;
int wa[Max],wb[Max],wsf[Max],wv[Max],sa[Max];
int rankk[Max],height[Max];
char str[Max];
int cmp(int *r,int a,int b,int k)
{
return r[a]==r[b]&&r[a+k]==r[b+k];
}
void getsa(int *r,int *sa,int n,int m)
{
int i, j, p, *x = wa, *y = wb;
for (i = 0; i < m; ++i) wsf[i] = 0;
for (i = 0; i < n; ++i) wsf[x[i]=r[i]]++;
for (i = 1; i < m; ++i) wsf[i] += wsf[i-1];
for (i = n-1; i >= 0; --i) sa[--wsf[x[i]]] = i;
for (j = 1, p = 1; p < n; j *= 2, m = p)
{
for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = 0; i < n; ++i) wv[i] = x[y[i]];
for (i = 0; i < m; ++i) wsf[i] = 0;
for (i = 0; i < n; ++i) wsf[wv[i]]++;
for (i = 1; i < m; ++i) wsf[i] += wsf[i-1];
for (i = n-1; i >= 0; --i) sa[--wsf[wv[i]]] = y[i];
for (swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
}
}
void calheight(int r[], int n)
{
int i, j, k = 0;
for (i = 1; i <= n; ++i) rankk[sa[i]] = i;
for (i = 0; i < n; height[rankk[i++]] = k)
for (k?k--:0, j = sa[rankk[i]-1]; r[i+k] == r[j+k]; k++);
}
int len,a[Max],d[Max][40];
void rmq_init(int* A, int n)
{
for(int i = 0; i < n; ++i)
d[i][0] = A[i];
for(int j = 1; (1<<j) <= n; ++j)
for(int i = 0; i + (1<<j) - 1 < n ; ++i)
d[i][j] = min(d[i][j-1], d[i + (1<< (j-1))][j-1]);
}
int ASK(int l,int r)
{
int k = 0;
while((1<<(k+1)) <= r-l + 1)
++k;
return min(d[l][k], d[r-(1<<k) + 1][k]);
}
int ask(int l,int r)
{
if (l == r)
return len - sa[r];
return ASK(l + 1, r);
}
int main()
{
int T,k;
scanf("%d",&T);
while(T--)
{
scanf("%d",&k);
scanf("%s",str);
len = strlen(str);
for(int i = 0;i < len;i++)
a[i] = str[i]-'a'+1;
a[len] = 0;
getsa(a,sa,len+1,30);
calheight(a,len);
rmq_init(height,len+1);
ll ans = 0;
for(int i = 1;i + k - 1 <= len;i++)
{
ans += ask(i,i+k-1);
if(i-1 > 0)
ans -= ask(i-1,i+k-1);
if(i+k <= len)
ans -= ask(i,i+k);
if(i-1 > 0 && i+k <= len)
ans += ask(i-1,i+k);
}
printf("%lld\n",ans);
}
return 0;
}
哈希
待续……