LOADING

加载过慢请开启缓存 浏览器默认开启

洛谷 P10537 九月

题目传送门

思路

这是一道交互题。

交互格式在这里就不说了。

考虑到:若 \([l,r]\) 这个区间是合法的,那么因为 \([1,l]\) 是合法的,所以 \([1,r]\) 是合法的,所以问题转化为,有多少个前缀是合法的。

对于一段区间,若所有的数要么出现 \(0\) 次,要么出现了 \(M\) 次,那么这就是合法的条件之一(要么都没记录,要么全记录)。这个可以用桶来实现。

还有就是掉叶子是否合法。假如这段区间中,存在一个非叶子节点的儿子没有掉完,并且他自己要掉,那么就是非法的,这个可以通过记录每个点的未掉的儿子个数,以及这个点是否需要掉来解决。

当满足以上两个条件时,这个前缀便是合法的,将答案 \(+1\) 即可。

时间复杂度 \(O(NM)\)

代码

注意是交互题。

#include<bits/stdc++.h>
using namespace std;
int solve(int N,int M,vector<int> F,vector<vector<int> >S);

const int MAXN=1e5+10;
int cnt,cnt2,ans,son[MAXN],t[MAXN];
bool flag[MAXN];

int solve(int N,int M,vector<int> F,vector<vector<int> >S){
    for(int i=0;i<N;i++) son[i]=t[i]=flag[i]=0;
    for(int i=1;i<N;i++) son[F[i]]++;
    cnt=N;cnt2=ans=0;
    for(int i=0;i<N-1;i++){
        for(int j=0;j<M;j++){
            t[S[j][i]]++;
            if(t[S[j][i]]==1) cnt--;
            if(t[S[j][i]]==M) cnt++;
            if(flag[S[j][i]]) continue;
            flag[S[j][i]]=true;
            if(son[S[j][i]]!=0) cnt2++;
            son[F[S[j][i]]]--;
            if(son[F[S[j][i]]]==0&&flag[F[S[j][i]]]) cnt2--;
        }
        if(cnt==N&&cnt2==0) ans++;
    }
    return ans;
}