K.K-Bag
题目链接-K.K-Bag
题目大意
一种叫
k
−
b
a
g
k-bag
k−bag的序列,这类序列由若干个从
1
−
k
1-k
1−k的排列依次排列组成,例如
1
,
2
,
3
,
2
,
1
,
3
,
3
,
2
,
1
1,2,3,2,1,3,3,2,1
1,2,3,2,1,3,3,2,1就是一个3-bag序列,现在又定义了
p
a
r
t
k
−
b
a
g
part\ k-bag
part k−bag,如果一个序列是一个
k
−
b
a
g
k-bag
k−bag的连续子串,那么这个序列就叫做
p
a
r
t
k
−
b
a
g
part\ k-bag
part k−bag序列,请你判断一个序列是否是
p
a
r
t
k
−
b
a
g
part\ k-bag
part k−bag序列
解题思路
滑
动
窗
口
问
题
滑动窗口问题
滑动窗口问题
- 首先我们要特判一下该序列中是否有大于
k
k
k的数字,显然如果存在大于
k
k
k的数字是不合法的,直接输出
NO
- 然后可以通过“切割”的方式把序列分割成若干个
1
1
1到
k
k
k的排列或部分排列;我们可以先统计区间内的不同元素的个数,如果区间内有
k
k
k个或
i
i
i个不同的数字说明该点可以用于切割,用数组
f[]
来记录该位置可不可以切 - 然后我们倒序统计区间内不同元素的个数,然后判断有没有区间内不同元素个数恰好等于该区间元素个数的,则说明这个点从后面可以切割,若它从前面也可以切割(
f[i]!=0
),则说明存在一种方案满足该序列是一个 p a r t k − b a g part\ k-bag part k−bag - 具体操作见代码
附上代码
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
#define lowbit(x) (x &(-x))
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f;
const int dir[4][2]={-1,0,1,0,0,-1,0,1};
const double PI=acos(-1.0);
const double e=exp(1.0);
const double eps=1e-10;
const int M=1e9+7;
const int N=5e6+10;
typedef long long ll;
typedef pair<int,int> PII;
typedef unsigned long long ull;
int a[N],f[N];
unordered_map<int,int> mp;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;
cin>>t;
while(t--){
mp.clear();
int n,k,ass=0,cnt=0;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]>k) ass=1;
}
if(ass){
cout<<"NO"<<endl;
continue;
}
memset(f,0,sizeof f);
f[0]=1;
for(int i=1;i<=n;i++){
if(i>k){
mp[a[i-k]]--;
if(mp[a[i-k]]==0) cnt--;
}
if(mp[a[i]]==0) cnt++;
mp[a[i]]++;
if(cnt==k||cnt==i)
f[i]=i-k>=0?f[i-k]:1;
}
cnt=0;
mp.clear();
for(int i=n;i>=max(n-k,0ll);i--){
if(f[i]&&cnt==n-i){
ass=1;
break;
}
if(mp[a[i]]==0) cnt++;
mp[a[i]]++;
}
if(ass) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}