Educational Codeforces Round 36 (Rated for Div. 2) 题解

Educational Codeforces Round 36 (Rated for Div. 2)

题目的质量很不错(不看题解做不出来,笑

Codeforces 920C

题意

给定一个\(1\)到\(n\)组成的数组,只可以交换某些相邻的位置,问是否可以将数组调整为升序的

解题思路

首先如果每个数都能通过交换到它应该到的位置,那么就可以调整为升序的。

但实际上交换是对称的,如果应该在的位置在当前位置前方的数都交换完成,那么整体就是排好序的,因为不可能所有不在相应位置的数都在相应位置的后方。

所以我们从\(1\)到\(n\)扫一遍,在扫描的过程中维护当前位置能向前交换的位置的最小值,这样就可以判断了

AC代码

#include <bits/stdc++.h>
using namespace std;
int n,pos[300020],num[300020];
string str;
bool judge()
{
    int maxpre=1;
    for (int i=1;i<=n;i++)
    {
        if(i>=2)
            if(str[i-2]==‘0‘)   maxpre=i;
        if(pos[i]>=i)   continue;
        if(maxpre>pos[i])   return false;
    }
    return true;
}
int main(int argc, char const *argv[])
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&num[i]);
        pos[num[i]]=i;
    }
    cin>>str;
    if(judge())
        puts("YES");
    else
        puts("NO");
    return 0;
}

Codeforces 920E

题意

给定一个无向图,求补图的连通分量数和每个连通分量的大小

点数\(n \le 200000\) ,边数\(m \le 200000\)

(原题?:bzoj1098)

解题思路

虽然直接对补图用\(BFS\)求连通分量数复杂度是\(O(n)\)的,但光建图复杂度就要\(O(n^2)\)了,所以直接建补图肯定是不行的

这里用到一个神奇的方法,在对原图\(BFS\)最开始维护一个所有未分配在连通分量中的点的集合,当前点不能到达的点就是补图能到达的点,将补图能到达的点加入队列继续\(BFS\),对于已经判断在某个连通分量的点,需要在集合中删去。

这个集合可以直接使用std::set<int>,也可以使用链表,在这里我使用链表

这样只需要建原图就可以对补图进行\(BFS\)了,复杂度\(O(n+m)\)

AC代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=200010;
vector <int> G[maxn];
int scc[maxn],scccnt;
int pre[maxn],nxt[maxn],vis[maxn],deled[maxn];
int n,m;
void del(int u)
{
    nxt[pre[u]]=nxt[u];
    pre[nxt[u]]=pre[u];
}
void bfs(int s)
{
    queue<int> Q;
    Q.push(s);
    del(s);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        if(vis[u])  continue;
        vis[u]=true;
        scc[scccnt]++;
        for (int v:G[u])
            deled[v]=true;
        for (int i=nxt[0];i<=n;i=nxt[i])
            if(!deled[i])
            {
                del(i);Q.push(i);
            }
        for (int v:G[u])
            deled[v]=false;
    }
    scccnt++;
}
int main(int argc, char const *argv[])
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n+1;i++)    pre[i]=i-1;
    for (int i=0;i<=n;i++)  nxt[i]=i+1;
    for (int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }

    for (int i=nxt[0];i<=n;i=nxt[i])
        if(!vis[i])
            bfs(i);

    sort(scc,scc+scccnt);
    printf("%d\n",scccnt);
    for (int i=0;i<scccnt;i++)
        printf("%d ",scc[i]);
    puts("");
    return 0;
}

Codeforces 920F

题意

定义\(D(x)= Card\{k:k| x,k \in N^+\}\)

给定数组\(a\),做如下操作:

replace l r:将\(a_l\)到\(a_r\)替换为\(D(a_i)\)

sum l r:输出\(a_l\)到\(a_r\)的和

点数\(n \le 300000\),操作数\(m \le 300000\) ,\(a_i \le 1000000\)

解题思路

\(D(x)\)可以直接用筛法求出,复杂度\(O(MAXN \log MAXN)\)

首先显然要用线段树进行维护,但是直接套线段树对区间的每个点都单点更新显然是过不了的

注意到对\(D(x)\)迭代收敛很快,根据官方题解,在数据范围内迭代不超过\(6\)次就可以收敛到\(2\)或\(1\)

我们可以用\(2\)棵线段树,一棵维护和,一棵维护最大值,当区间更新时对整个区间进行递归地更新,如果当前子树的最大值$ \le 2$, 那么可以直接返回,这样对于每个点最多不更新超过\(6\)次

复杂度\(O(m \log n+MAN \log MAXN)\)

AC代码

#include <bits/stdc++.h>
using namespace std;
const int maxnum=1e6+6;
const int maxn=3e5+7;
int D[maxnum],a[maxn];
int n,m;
long long sumv[(maxn<<2)+5];
int maxv[(maxn<<2)+5];
void build(int now,int l,int r)
{
    if(l==r)
    {
        maxv[now]=sumv[now]=a[l];
        return;
    }
    int mid=l+((r-l)>>1);
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    sumv[now]=sumv[now<<1]+sumv[now<<1|1];
    maxv[now]=max(maxv[now<<1],maxv[now<<1|1]);
}
void update(int now,int l,int r,int ul,int ur)
{
    if(maxv[now]<=2)    return; //关键
    if(l==r)
    {
        maxv[now]=sumv[now]=D[sumv[now]];
        return;
    }
    int mid=l+((r-l)>>1);
    if(ul<=mid) update(now<<1,l,mid,ul,ur);
    if(ur>mid) update(now<<1|1,mid+1,r,ul,ur);
    sumv[now]=sumv[now<<1]+sumv[now<<1|1];
    maxv[now]=max(maxv[now<<1],maxv[now<<1|1]);
}
long long query_sum(int now,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)    return sumv[now];
    int mid=l+((r-l)>>1);
    long long ans=0;
    if(ql<=mid) ans+=query_sum(now<<1,l,mid,ql,qr);
    if(qr>mid)  ans+=query_sum(now<<1|1,mid+1,r,ql,qr);
    return ans;
}

void pre_solve()
{
    for (int i=1;i<=1e6;i++)
    {
        for (int j=i;j<=1e6;j+=i)
            D[j]++;
    }
}

int main(int argc, char const *argv[])
{
    pre_solve();
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    build(1,1,n);
    while(m--)
    {
        int t,l,r;scanf("%d%d%d",&t,&l,&r);
        if(t==1)
            update(1,1,n,l,r);
        else
            printf("%I64d\n",query_sum(1,1,n,l,r));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/falseangel/p/8441015.html

时间: 2024-08-08 18:47:24

Educational Codeforces Round 36 (Rated for Div. 2) 题解的相关文章

Educational Codeforces Round 36 (Rated for Div. 2)

Educational Codeforces Round 36 (Rated for Div. 2) F. Imbalance Value of a Tree You are given a tree T consisting of n vertices. A number is written on each vertex; the number written on vertex i is ai. Let's denote the function I(x,?y) as the differ

Educational Codeforces Round 36 (Rated for Div. 2) ---d

D. Almost Acyclic Graph 首先判环可以用拓扑来实现. 暴力解法自然是枚举每一条边,删除,判断是否存在环. 解法一: 对于指向同一个点的边,在拓扑排序中看删除他们事实上是等价的,即那个点入度-1,那么我们枚举所有的点即可. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int inf=1e5+10; 4 int n,m; 5 int tot,fi[inf],nxt[inf],to[inf],in[inf];

Educational Codeforces Round 36 (Rated for Div. 2) E. Physical Education Lessons(动态开点线段树)

链接: https://codeforces.com/problemset/problem/915/E 题意: This year Alex has finished school, and now he is a first-year student of Berland State University. For him it was a total surprise that even though he studies programming, he still has to atten

Educational Codeforces Round 36 (Rated for Div. 2) G. Coprime Arrays

求a_i 在 [1,k]范围内,gcd(a_1,a_2...,a_n) = 1的a的数组个数. F(x)表示gcd(a_1,a_2,...,a_n) = i的a的个数 f(x)表示gcd(a_1,a_2,...,a_n) = ki的a的个数(实际上就是i的倍数) f(x) = segma(x | d) F(d) F(x) = segma(x | d) mu(d / x) * f(d) F(1) = segma(d,1,k) mu(d) * f(d) f(d) = (k / d)^n 由于k变化时

Educational Codeforces Round 80 (Rated for Div. 2) 题解

Deadline Yet Another Meme Problem Two Arrays Minimax Problem Messenger Simulator Deadline \[ Time Limit: 2 s\quad Memory Limit: 256 MB \] 这是个对勾函数,所以最小的话是在 \(sqrt\) 位置,所以只要找这附近的数字就可以了. view /************************************************************

Educational Codeforces Round 58 (Rated for Div. 2) (题解)

C题卡了一个小时, 又被教育场教育了... A. Minimum Integer 大意:求不在$[l,r]$范围内的最小被$d$整除的数 模拟 #include <iostream> #define REP(i,a,n) for(int i=a;i<=n;++i) using namespace std; int main() { int t; scanf("%d", &t); REP(i,1,t) { int l,r,d; scanf("%d%d%

Educational Codeforces Round 78 (Rated for Div. 2) 题解

Shuffle Hashing A and B Berry Jam Segment Tree Tests for problem D Cards Shuffle Hashing \[ Time Limit: 2 s\quad Memory Limit: 256 MB \] 处理出 \(s_1\) 中各个字符出现的次数,然后双指针维护 \(s_2\) 中每一段长度为 \(len(s_1)\) 的串中字符出现的次数,如果存在某一段和 \(s_1\) 的字符次数相同,则是答案. view #inclu

Educational Codeforces Round 69 (Rated for Div. 2) B - Pillars

Educational Codeforces Round 69 (Rated for Div. 2) B - Pillars There are n pillars aligned in a row and numbered from 1 to n. Initially each pillar contains exactly one disk. The i-th pillar contains a disk having radius ai. You can move these disks

Educational Codeforces Round 71 (Rated for Div. 2) A - There Are Two Types Of Burgers

原文链接:https://www.cnblogs.com/xwl3109377858/p/11404050.html Educational Codeforces Round 71 (Rated for Div. 2) A - There Are Two Types Of Burgers There are two types of burgers in your restaurant — hamburgers and chicken burgers! To assemble a hamburg