Codeforces Round 595(div3) 题解

Codeforces Round 595 contest1249 题解


地址: 传送门.

A:

题目大意:给你n个数字,同一个组的数字大小相减的绝对值不能等于1,问最多可以分为几个组
题解:答案只能为1或者2,将数组排序,如果相邻的两个数的差值等于1,则答案为2,否则答案为1

AC代码:

#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        vector<int> a(n);
        for(auto& it:a)
            cin>>it;
        sort(a.begin(),a.end());
        int ans=1;
        for(int i=0;i<n-1;i++)
        {
            if(a[i+1]-a[i]==1)
            {
                ans=2;
                break;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

B:

题意:给定一个长为n的排列p,对于每一个i需要通过pi来计算多少次才能查找到自己
题解:直接dfs判环,环的大小就是所求每一个i对应的值

AC代码:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define gc(x) getchar(x)
#define INF 0x3f3f3f3f
#define debug(x) cout<< #x " = "<<(x)<<endl;
#define pc(x) putchar(x)
using namespace std;
typedef long long ll;

template<typename T>
inline void read(T &x) {
    x = 0;
    int f = 1;
    char ch = gc();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-') f = -1;
        ch = gc();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = gc();
    }
    x *= f;
}

template<typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }

template<typename T>
inline void write(T x) {
    if (x < 0) putchar('-'), write(-x);
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

const int N = 2e5+10;
int a[N],vis[N],ans[N];
vector<int> G[N],v;

void dfs(int u,int t)
{
    if(vis[u])
    {
        for(int i=0;i<v.size();i++)
            ans[v[i]]=t-vis[u];
        v.clear();
        return;
    }
    vis[u]=t;
    v.emplace_back(u);
    for(int i=0;i<G[u].size();i++)
    {
        int j=G[u][i];
        dfs(j,t+1);
    }
}

signed main() {
    int T;
    read(T);
    while (T--)
    {
        memset(vis,0,sizeof vis);
        memset(ans,0,sizeof ans);
        int n;
        read(n);
        for(int i=1;i<=n;i++)
        {
            read(a[i]);
            G[i].emplace_back(a[i]);
        }
        for(int i=1;i<=n;i++)
            if(!vis[i])
                dfs(i,1);
        for(int i=1;i<=n;i++)
        {
            write(ans[i]);pc(' ');
        }
        pc(endl);
        for(int i=0;i<=n;i++)
            G[i].clear();
    }
    return 0;
}

C

题意:给定一个n,求找到一个大于等于n的数m,m由3的y次幂构成,y只能出现一次,问最小的m是多少
题解:最大的数为3的38次幂,我们利用某个数的n次幂比前n-1项的次幂之和还要大的原理,从大到小来比较3的y次幂与n,如果n大,则减去3的y次幂,并标记,之后再从小到大查看标记,如果没有被标记,说明此时的n比这个3的y次幂要小,那么直接加上该数并结束循环就可以得到答案

AC代码:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define  int ll
#define gc(x) getchar(x)
#define INF 0x3f3f3f3f
#define debug(x) cout<< #x " = "<<(x)<<endl;
#define pc(x) putchar(x)
using namespace std;
typedef long long ll;

template<typename T>
inline void read(T &x) {
    x = 0;
    int f = 1;
    char ch = gc();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-') f = -1;
        ch = gc();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = gc();
    }
    x *= f;
}

template<typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }

template<typename T>
inline void write(T x) {
    if (x < 0) putchar('-'), write(-x);
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

const int N = 39;
int t[N],vis[N];

signed main() {
    t[0]=1ll;
    for(int i=1;i<N;i++)
        t[i]=3*t[i-1];
    int T;
    read(T);
    while (T--)
    {
        memset(vis,0,sizeof vis);
        int n;
        read(n);
        int ans=0;
        for(int i=N-1;~i;i--)
            if(n>t[i])
            {
                n -= t[i];
                ans += t[i];
                vis[i]=1;
            }
        for(int i=0;i<N;i++)
        {
            if(vis[i])
            {
                ans-=t[i];
            } else{
                ans+=t[i];
                break;
            }
        }
        write(ans);pc(endl);
    }
    return 0;
}

D:

题意:给定n个线段和一个k,如果某个区间被线段覆盖超过k次,则删除掉该线段,问最少删除多少个线段
题解:我们先将给定的线段排序,先按照右端点从小到大排序,再按照左端点排序,如果覆盖的次数大于k,则删除后边的线段,即贪心的删除最长的线段,可以通过set的排序功能来实现,也可以通过线段树,每次更新前先查询是否可以覆盖,通过查询来更新线段树或者更新答案

AC代码:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define gc(x) getchar(x)
#define INF 0x3f3f3f3f
#define debug(x) cout<< #x " = "<<(x)<<endl;
#define pc(x) putchar(x)
using namespace std;
typedef long long ll;

template<typename T>
inline void read(T &x) {
    x = 0;
    int f = 1;
    char ch = gc();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-') f = -1;
        ch = gc();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = gc();
    }
    x *= f;
}

template<typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }

template<typename T>
inline void write(T x) {
    if (x < 0) putchar('-'), write(-x);
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

const int MAXN = 2e5+10;

vector< pair< int, int > > v[MAXN];

signed main()
{
    int n,c;
    read(n,c);
    for(int i=1;i<=n;i++)
    {
        int l,r;
        read(l,r);
        v[l].emplace_back(r,i);
    }
    set<pair<int,int> > st;
    vector<int> u;
    for(int i=1;i<=MAXN;i++)
    {
        while(!st.empty()&&st.begin()->first<i) st.erase(st.begin());
        for(int j=0;j<v[i].size();j++) st.emplace(v[i][j]);
        while(st.size()>c)
        {
            u.emplace_back((--st.end())->second);
            st.erase(--st.end());
        }
    }
    write(u.size());pc(endl);
    for(auto it:u)
    {
        write(it);pc(' ');
    }
    pc(endl);
    return 0;
}

E

题意:动态规划题,上楼梯,每层可以选择楼梯或者电梯,选择电梯的话需要加上一个给定的等待时间,问上到每一层需要的最小时间
题解:这一层的时间由下一层的时间得到,如果这一层选择楼梯,答案是下一层选择楼梯和电梯之间的最小值加上楼梯的时间,如果这一层选择电梯,答案是下一层选择楼梯的时间加上等待时间和下一层选择电梯的时间的最小值加上电梯的时间

AC代码:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define gc(x) getchar(x)
#define INF 0x3f3f3f3f
#define debug(x) cout<< #x " = "<<(x)<<endl;
#define pc(x) putchar(x)
using namespace std;
typedef long long ll;

template<typename T>
inline void read(T &x) {
    x = 0;
    int f = 1;
    char ch = gc();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-') f = -1;
        ch = gc();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = gc();
    }
    x *= f;
}

template<typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }

template<typename T>
inline void write(T x) {
    if (x < 0) putchar('-'), write(-x);
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

const int N = 2e5+10;
int a[N],b[N],ans[N],ans1[N];

signed main() {
    memset(ans,0,sizeof ans);
    memset(ans1,0,sizeof ans1);
    int n,c;
    read(n,c);
    for(int i=1;i<n;i++)
    {
        read(a[i]);
    }
    for(int i=1;i<n;i++)
        read(b[i]);
    ans1[0]=c;
    for(int i=1;i<n;i++)
    {
        ans[i]=min(ans[i-1],ans1[i-1])+a[i];
        ans1[i]=min(ans[i-1]+c,ans1[i-1])+b[i];
    }
    for(int i=0;i<n;i++)
    {
        write(min(ans[i],ans1[i]));pc(' ');
    }
    pc(endl);
    return 0;
}

F

题意:给一个树,求每对点之间的距离大于k的最大权值和
题解:n<200,所以直接从深度为n的地方直接暴力求最大点集合,每次选择一个点,并且将距离小于k的点的值减去该点的值,如果减去之后值还大于0的话,说明这个点比当前选择的点更优秀,则加上该点的值

AC代码:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define endl '\n'
#define gc(x) getchar(x)
#define INF 0x3f3f3f3f
#define debug(x) cout<< #x " = "<<(x)<<endl;
#define pc(x) putchar(x)
using namespace std;
typedef long long ll;
 
template<typename T>
inline void read(T &x) {
    x = 0;
    int f = 1;
    char ch = gc();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-') f = -1;
        ch = gc();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = gc();
    }
    x *= f;
}
 
template<typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
 
template<typename T>
inline void write(T x) {
    if (x < 0) putchar('-'), write(-x);
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}
 
const int N=210;
int a[N];
vector<int> G[N],d[N];
int c;

void DFS(int u,int t,int fa)
{
	d[t].emplace_back(u);
	for(int i=0;i<G[u].size();i++)
	{
		int v=G[u][i];
		if(v==fa) continue;
		DFS(v,t+1,u);
	}
}
int res=0;
void dfs(int u,int t,int fa)
{
    if(t>c) return;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==fa) continue;
        a[v]-=res;
        dfs(v,t+1,u);
    }
}

signed main()
{
	memset(d,0,sizeof d);
    int n;
    read(n,c);
    for(int i=1;i<=n;i++)
    {
    	read(a[i]);
	}
	for(int i=1;i<n;i++)
	{
		int l,r;
		read(l,r);
		G[l].emplace_back(r);
		G[r].emplace_back(l);
	}
	DFS(1,1,0);
	int ans = 0;
	for(int i=n;i>=1;i--)
    {
	    for(int j=0;j<d[i].size();j++)
        {
	        if(a[d[i][j]]>0)
            {
	            ans+=a[d[i][j]];
	            res=a[d[i][j]];
	            dfs(d[i][j],1,0);
            }
        }
    }
	write(ans);
	pc(endl);
    return 0;
}

第一次写博客,不喜勿喷

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值