T*n已经最大已经是10的7次方了,所以这道题虽然暴力枚举前面不完整歌单的情况的思路好想,但是必须用滑动窗口(或者叫尺取法)的技巧来预处理两个数组,这样可以O(n)完成每组数据。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<list> #include<deque> #include<vector> #include<algorithm> #include<stack> #include<queue> #include<cctype> #include<sstream> using namespace std; #define pii pair<int,int> #define LL long long int const double eps=1e-10; const int INF=1000000000; const int maxn=100000+10; int T,n,s,a[maxn],t[maxn],ok[maxn],jie[maxn]; void qian()//预处理前面的非完整list,jie[i]==1表示 //最前面那份不完整list能以a[i]结尾 { jie[0]=1; memset(t,0,sizeof(int)*(s+1)); for(int i=1; i<s; i++) { if(i-1>=n||t[a[i-1]]==0) { if(i-1<n) t[a[i-1]]++; jie[i]=1; } else { for(int j=i; j<s; j++) { jie[j]=0; return; } } } } void gao()//预处理,ok[i]==1表示以i开始的连续s个数可以组成一个list { int num=0; memset(t,0,sizeof(int)*(s+1)); for(int i=0; i<s; i++) { if(i>=n)//空位 { num++; continue; } if(t[a[i]]==1) { ok[0]=0; t[a[i]]++; } else { num++; t[a[i]]++; } } if(num==s) ok[0]=1; for(int i=1; i<n; i++) { if(t[a[i-1]]==1) num--; t[a[i-1]]--; if(i+s-1>=n||t[a[i+s-1]]==0) num++; if(i+s-1<n) t[a[i+s-1]]++; if(num==s) ok[i]=1; else ok[i]=0; } } int main() { //freopen("in1.txt","r",stdin); scanf("%d",&T); while(T--) { scanf("%d%d",&s,&n); memset(ok,-1,sizeof(int)*(n+1)); for(int i=0; i<n; i++) { scanf("%d",&a[i]); } int ans=0; gao(); qian(); for(int i=0; i<s; i++) { if(jie[i])//最前面的逗号点在i之前 { bool w=1; for(int j=i; j<n; j+=s) //以j开始新的list { if(ok[j]!=1) { w=0; break; } } if(w==1) ans++; } else { break; } } printf("%d\n",ans); } return 0; }
时间: 2024-10-27 12:47:07