Codeforces Round #453 (Div. 2)(A-E题解)

本文解析了五道涉及动态规划、图论、树结构等核心算法的编程题目,提供了详细的代码实现与思路说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A:pig站在传送带上只能在传送带上移动的情况下判断是否能够到达m初始位置0

题解:用dp[i]表示pig能不能到达接着转移方程就是在传送在dp[i] = max(dp[i-1],dp[i])即可

 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
#define root 1,1,n
#define ls 2*rt
#define rs 2*rt+1
#define mid (L+R)/2
#define lson ls,L,mid
#define rson rs,mid+1,R
const int mx = 1e5+5;
int l[mx];
int r[mx];
int dp[mx];
int main(){
    int n,m;
    memset(dp,0,sizeof(dp));
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++)
        scanf("%d%d",&l[i],&r[i]);
    dp[0] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = l[i]+1; j <= r[i]; j++)
            dp[j] = max(dp[j-1],dp[j]);
    if(dp[m])
        puts("YES");
    else
        puts("NO");
    return 0;
}


B:让你涂一棵树的颜色,涂完改结点后其所有子树都会变成该颜色,要求你涂成特定的颜色需要涂多少步

 

题解:直接从上往下涂判断是否为想要的颜色即可

 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
#define root 1,1,n
#define ls 2*rt
#define rs 2*rt+1
#define mid (L+R)/2
#define lson ls,L,mid
#define rson rs,mid+1,R
const int mx = 1e5+5;
vector<int>g[mx];
int col[mx];
int ans;
void dfs(int u,int fa,int s){
    if(s!=col[u])
        ans++;
    for(auto v: g[u]){
        if(v!=fa){
            dfs(v,u,col[u]);
        }
    }
}
int main(){
    int n,m;
    int a;
    ans = 0;
    scanf("%d",&n);
    for(int i = 2; i <= n; i++){
        scanf("%d",&a);
        g[a].push_back(i);
    }
    for(int i = 1; i <= n; i++)
        scanf("%d",&col[i]);
    dfs(1,0,0);
    printf("%d\n",ans);
    return 0;
}


C::给你一课树,深度0-n,深度为然后是0-n的树判断是否能构造出不同构的树

 

题解:如果有两个以上高度连续且个数都为2以上的话肯定能构造出不同构的树,接着让同一高度的结点一个指向开始结点一个指向末尾结点即可

 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
#define root 1,1,n
#define ls 2*rt
#define rs 2*rt+1
#define mid (L+R)/2
#define lson ls,L,mid
#define rson rs,mid+1,R
const int mx = 1e5+5;
int a[mx];
int main(){
    int n,m;
    scanf("%d",&n);
    int ok = 1;
    int sum = 0;
    for(int i = 0; i <= n; i++){
        scanf("%d",&a[i]);
        sum += a[i];
    }
    for(int i = 1; i <= n; i++)
        if(a[i]>=2&&a[i-1]>=2)
            ok = 0;
    if(ok)
        puts("perfect");
    else{
        puts("ambiguous");
        int pre = 0;
        int len = 1;
        for(int i = 0; i <= n; i++){
            for(int j = 1; j <= a[i]; j++){
                printf("%d%c",pre,len==sum?'\n':' ');
                len++;
            }
            pre = len-1;
        }
        pre = 0;
        len = 1;
        int s = 0;
        for(int i = 0; i <= n; i++){
            for(int j = 1; j <= a[i]; j++){
                printf("%d%c",j%2==0?s:pre,len==sum?'\n':' ');
                len++;
            }
            pre = len-1;
            s = len-a[i];
        }
    }
    return 0;
}

 

 

D:给你一个公式然后判断多项式到达B等于0需要多少步

题解:设p1 = 1, p2 = x

p(n) = x*p(n-1) + p(n-2)即可

因为限制了系数只能为-1,0,1所以我们求得时候取膜2即可

 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mx = 1e5+5;
int a[300],b[300],c[300];
	int n;
void calc(){
	int *x,*y,*z;
	x = a;
	y = b;
	z = c;
	for(int i = 1; i < n; i++){
		memset(z,0,sizeof(c));
		for(int j = 0; j <= i; j++){
			z[j+1] = x[j];
			
		}
		for(int j = 0; j < i; j++){
			z[j] = (z[j]+y[j])%2;
		//	printf("%d",y[j]);
		}
		swap(x,z);
		swap(z,y);
	}
	printf("%d\n",n);
	for(int i = 0; i <= n; i++)
		printf("%d%c",x[i],i==n?'\n':' ');
	n--;
	printf("%d\n",n);
	for(int i = 0; i <= n; i++)
		printf("%d%c",y[i],i==n?'\n':' ');
}
int main(){
	scanf("%d",&n);
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	a[0] = 0;
	a[1] = 1;
	b[0] = 1;
	calc();	
	return 0;
}

 

E:给你n个点的无向图,保证没有偶数点的环,有q个查询,每次给l,r问只保留l,r编号的点,问有多少对区间内的点构成二分图

 

题解:如果都没有环的情况是(n+1)*n/2那么考虑一下有环的化我如果是这个环内编号的最小的或者比他小的点那么我只能延伸到环的最大点-1接着当给你l,r的时候我只要找出最右边的那个有环的最小点加1即可,这样分成两部分就是sum[l]-sum[x]+(r-x+2)*(r-x+1)/2,这些我们可以预处理一下在r位置的最右边的环的点是哪一个,接着就是求环我们当碰到已经遍历过的点那么我们可以用一个栈存一下一直后退直到栈顶的元素是我们遍历到的点即可.最后我这个点可能不在环内用另外一个数字标记一下即可

 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<stack>
#include<set>
using namespace std;
typedef long long int ll;
const int mx = 3e5+5;
stack<int>s;
int front[mx];
vector<int>g[mx];
int pre[mx];
int Max[mx],Min[mx];
ll sum[mx];
void dfs(int u,int fa){
    pre[u] = 1;
    s.push(u);
    for(auto v: g[u]){
        if(v!=fa){
            if(pre[v]==0) dfs(v,u);
            else if(pre[v]==1){
                int x = u,y = u;
                while(!s.empty()){
                    int z = s.top();
                    s.pop();
                    x = min(z,x);
                    y = max(z,y);
                    if(z==v)    break;
                }
                Max[y] = x;
                Min[x] = y;
            }
        }
    }
    if(!s.empty()&&s.top()==u) s.pop();
    pre[u] = 2;
}
int main(){
    int n,m,q;
    scanf("%d%d",&n,&m);
    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 = 0; i <= n+1; i++)
            Max[i] = 0,Min[i] = n+1;
    for(int i = 1; i <= n; i++)
        if(!pre[i])
            dfs(i,i);
    int x,y;
    for(int i = n; i >= 1; i--){
        Min[i] = min(Min[i+1],Min[i]);
        sum[i] = sum[i+1] + Min[i]-i;
    }
    for(int i = 1; i <= n; i++){
        Max[i] = max(Max[i-1],Max[i]);
        cout<<Max[i]<<endl;
    }
    scanf("%d",&q);
    while(q--){
        int l,r;
        scanf("%d%d",&l,&r);
        x = max(l,Max[r]+1);
        //cout<<x<<endl;
        ll ans = sum[l]-sum[x];
        //cout<<ans<<endl;
        ans  += 1ll*(r-x+2)*(r-x+1)/2;
        printf("%I64d\n",ans);
    }
    return 0;
}

 

 

 

给你

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值