tg 82 solution

T1

对于每个包,时间复杂度要求\(O(n)\)\(O(n\log n)\)

Subtask 1

这个包考虑\(O(n\log n)\)的二分就可以过,下面会讲

Subtask 2

考虑充分利用"连续"这个性质

事实上我们考虑查\(i\)\(i-1\),相同就没事,否则开个新连续段

Subtask 3

\(cnt\leq 3,n\leq 1000,Q\leq 2000\)

这一部分的做法显然不能\(O(n\log n)\),考虑\(O(n)\)

注意到\(cnt\leq 3\),我们对于每一种颜色,记录它上一个出现的位置,记为\(last\)

对于每个\(i\),左端点定\(last\)从后往前扫,如果查询颜色数同\(i-1\)那说明\(i\)颜色同左端点

否则接着扫就完了,扫完记得更新\(last\)

询问\(3\cdot n\),最后一个\(last\)没必要扫,询问\(2\cdot n\)

Subtask 4

上面的东西询问变成\(3\cdot n\),对上面的东西做个优化

手动二分一下,倒着按\(3,2,4,1\)的顺序,不写很详细了

然后就没有然后了,对于每个点每个分支至多查\(2\)

查询\(2\cdot n\)

这一部分没讲太细,所以放码了

点击查看代码
struct node{
    int id,val;
    bool operator<(node y){return id<y.id;}
}l[o];
int Query(int l,int r){
    if(q[l].find(r)!=q[l].end())return q[l][r];
    return q[l][r]=query(l,r);
}
void solve4(int n){
    memset(l, 0, sizeof(l));
    l[1].val = l[1].id = 1;
    l[2].val = 2; l[3].val = 3; l[4].val = 4;
    memset(c, 0, sizeof(c));
    c[1] = 1;
    ans.emplace_back(1);
    for(int i=2;i<=n;i++){
        sort(l + 1,l + 5);
        if(query(max(l[3].id, 1),i) == 3){
            if(query(max(1, l[2].id), i) == 3){
                c[i] = l[2].val;
                l[2].id = i;
            }
            else{
                c[i] = l[1].val;
                l[1].id = i;
            }
        }
        else{
            if(query(max(1, l[4].id), i) == 1){
                c[i] = l[4].val;
                l[4].id = i;
            }
            else{
                c[i] = l[3].val;
                l[3].id = i;
            }
        }
        ans.emplace_back(c[i]);
    }
    // for(int i=1;i<=n;i++)ans.push_back(c[i]);    
}
Subtask 5

出题人不会放出\(cnt=n\)的数据的

如果有,那直接\([1,n]\)挨个装一遍

否则,找到第一个重的位置,然后直接把重掉的位置换掉

如果重复,会有\([1,pos]\)的数量不是\(pos\)

扫第二遍重复的时候就是把\(1\)换成\(i\),重复就是区间数量不等于\(pos-i+1\)

查询次数\(2\cdot n\)

Subtask 6

这个放给暴力

Subtask 7

这个时候暴力废了,二分就完事了

如果端点一定,那区间长度增大,查询结果单调不降

考虑二分找到上一个和它相同的点

如果在\(mid\)位置,查询\([mid,i-1]\)结果小于\([mid,i]\)说明应该左移,否则右移

如果直接查询的话,询问\(2\cdot n\log n\)

考虑去掉常数,因为\([mid,i-1]\)这一段是知道的,所以直接在已有信息上暴扫就好了

花费在暴扫上的时间复杂度\(O(n^2\log n)\),查询\(n\log n\)

T2

把连续段缩到一起,问题可以有很简洁的表述方式。

对于长度为\(n\)的序列\(a\),每个位置还有一个值\(c\)表示连续段长度。

每次选择\(i<j\)\(a[i]=a[j]\),操作是--c[i],++c[j]

每种颜色是独立的,只用考虑可以得到哪些c,这个可以用前缀和限制。

问题转化成了普通的子序列匹配问题。

T3

没有细想,直接看沈老师题解

问题明显是构造出连通图。

连通图至少有\(n-1\)条边,所以奇数的段不能超过两个。

这个就是存在解的充要条件。

把奇数段放在头尾,构造\(a[1]-1,a[2],a[3],a[m]+1\)即可,

画个图很清楚,好像这样构造出来是一条链。

T4

posted @ 2022-11-10 21:26  2K22  阅读(23)  评论(0)    收藏  举报