牛客周赛 Round 8【题解完成】

64 阅读3分钟
题目难度知识点
A 小美的排列询问签到
B 小美走公路枚举
C 小美的排列构造构造
D 小美的树上染色★★树形DP

image.png D题想到了树形DP,但是写wa了,确实不会但理论上是应该要做出来的。

小美的排列询问

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
int a[N],st[N],n;
int main(void)
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i],st[a[i]]=i;
    int x,y; cin>>x>>y;
    int temp=abs(st[x]-st[y]);
    if(temp==1) puts("Yes");
    else puts("No");
    return 0;
}

小美走公路

打表找规律,挺容易发现的,算是cf中比较简单和经典的构造题。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL n,a[N],x,y;
int main(void)
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    cin>>x>>y;
    if(x>y) swap(x,y);
    LL ans1=0,ans2=0;
    for(int i=x;i<y;i++) ans1+=a[i];
    for(int i=1;i<x;i++) ans2+=a[i];
    for(int i=y;i<=n;i++) ans2+=a[i];
    cout<<min(ans1,ans2);
    return 0;
}

小美的排列构造

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*5+10;
typedef long long int LL;
LL n,a[N],ans=1e9,b[N];
int main(void)
{
    cin>>n;
    /*for(int i=0;i<n;i++) a[i]=i+1;
    do
    {
        LL minv=1e9,maxv=-1e9;
        for(int i=1;i<n;i++)
        {
            minv=min(minv,a[i]+a[i-1]);
            maxv=max(maxv,a[i]+a[i-1]);
        }
        if(maxv-minv<ans)
        {
            ans=maxv-minv;
            for(int i=0;i<n;i++) b[i]=a[i];
        }
    }while(next_permutation(a,a+n));
    for(int i=0;i<n;i++) cout<<b[i]<<" ";*/
    for(int i=0,j=1;i<n;i+=2,j++) a[i]=j;
    for(int i=1,j=n;i<n;i+=2,j--) a[i]=j;
    for(int i=0;i<n;i++) cout<<a[i]<<" ";
    return 0;
}
/*
3
2 1 3
4
1 4 2 3 
5
1 5 2 4 3
6
1 6 2 5 3 4
*/

小美的树上染色

image.png

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*5+10;
LL w[N],n,dp[N][2];//表示以i为根的子树,j==0表示该点没选,j==1表示该点选了
vector<int>ve[N];
bool check(LL x)
{
    LL res=sqrt(x);
    while(res*res<x) res++;
    while(res*res>x) res--;
    return res*res==x;
}
void dfs(int u,int fa)
{
    dp[u][0]=0,dp[u][1]=0;
    LL sum=0;
    for(int i=0;i<ve[u].size();i++)//该点没有染色,那么其子节点可以染色或者不然
    {
        int j=ve[u][i];
        if(j==fa) continue;
        dfs(j,u);
        sum+=max(dp[j][1],dp[j][0]);
    }
    dp[u][0]=sum;
    for(int i=0;i<ve[u].size();i++)//尝试该点染色,那个以为着其子节点有一个需要一定不能染色。
    {
        int j=ve[u][i];
        if(j==fa) continue;
        if(check(w[u]*w[j]))//选中该点和u进染色了
            dp[u][1]=max(dp[u][1],sum-max(dp[j][0],dp[j][1])+dp[j][0]+2);
            //总的-减去该子树的贡献+该子树不染色的贡献+该点和u染色的2个。
    }
}
int main(void)
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>w[i];
    for(int i=1;i<=n-1;i++)
    {
        int a,b; cin>>a>>b;
        ve[a].push_back(b);
        ve[b].push_back(a);
    }
    dfs(1,-1);
    cout<<max(dp[1][0],dp[1][1]);
    return 0;
}