做法:dp[i] = dp[i-1] + (i-k+1...i这段符合+1,否则+0)。如何判断这一段符不符合,找出这段的最大值,最小值,如何差值==k-1,并且里面的数没有重复,那么就可以+1,否则,就不能+1。最大值最小值用RMQ预处理一下是nlogn的复杂度,然后查找操作,因为长度一定所以就是o(1),问题的关键就是如何判断这个区间里面是否有重复的数,(n*k)的复杂度水过去的。。。,rep[i][j]表示i-j+1...i这个串是否有重复的,那么rep[i][j] = rep[i-1][j-1] || rep[i][j-1] || (num[i] == num[i-j+1]) 。然后就直接写了,然而我比赛搞了一半去装电脑去了。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
using namespace std;
int n,m,k,k_tw;
int num[11111];
int maxx[11111][15],minx[11111][15];
int dp[11111];
bool rep[11111][1111];
void INIT_RMQ(int bit){
FOR(i,0,n){
maxx[i][0] = minx[i][0] = num[i];
}
FOR(j,1,bit+1){
IFOR(i,n-1,-1){
if((i+(1<<(j-1))) < n){
maxx[i][j] = max(maxx[i][j-1],maxx[i+(1<<(j-1))][j-1]);
minx[i][j] = min(minx[i][j-1],minx[i+(1<<(j-1))][j-1]);
}
}
}
FOR(i,0,n) rep[i][1] = 0;
FOR(j,2,1002){
FOR(i,j-1,n){
if(rep[i-1][j-1] || rep[i][j-1] || num[i] == num[i-j+1]){
rep[i][j] = 1;
continue;
}
rep[i][j] = 0;
}
}
}
void solve(){
if(rep[k-1][k] || max(maxx[0][k_tw],maxx[k-(1<<k_tw)][k_tw])-min(minx[0][k_tw],minx[k-(1<<k_tw)][k_tw]) != k-1) dp[k-1] = 0;
else dp[k-1] = 1;
FOR(i,k,n){
dp[i] = dp[i-1];
if(!rep[i][k] && max(maxx[i-k+1][k_tw],maxx[i+1-(1<<k_tw)][k_tw])-min(minx[i-k+1][k_tw],minx[i+1-(1<<k_tw)][k_tw]) == k-1){
dp[i]++;
}
}
}
int main()
{
//freopen("test.in","r",stdin);
int tCase = 0;
while(~scanf("%d%d",&n,&m)){
printf("Case #%d:\n",++tCase);
FOR(i,0,n) scanf("%d",&num[i]);
int tem = 0;
while((1<<tem) < n){
tem++;
}
tem--;
INIT_RMQ(tem);
FOR(i,0,m){
scanf("%d",&k);
k_tw = 0;
while((1 << k_tw) <= k){
k_tw ++;
}
k_tw--;
solve();
printf("%d\n",dp[n-1]);
}
}
return 0;
}