• 2021 ICPC 南京站+上海站 部分题解


    CSDN话题挑战赛第2期

    再一次发现一个无比无比菜的自己。。。。

    H. Crystalfly

    本题难得倒不是思路,是代码的实现。看了下其他大佬的实现,真的惊呼太优雅了。
    思路:
    1.对于这样的一棵树来说,t的值只能取1到3,可发现2秒实在是没有价值。如果一个点是3s,那说明可去其他1s或3s的点拿完,再去拿这个点的值。
    2.如果从x点出发,走向z点,而y点的值是3s,说明可以去完z点转向去y点,这样势必会放弃z点孩子结点的点数。
    3.因此采用树形dp来记录各种状态。
    //dp[u][0]表示不取以u为根的孩子的最大点数
    //dp[u][1]表示取以u为根获得的最大点数
    状态的转移:
    一般情况:dp[u][1]=max(dp[u][1],dp[u][0]+a[v]);表示走向哪个孩子,获得的点数最大
    如果一个孩子结点的t值为3:说明这个结点y的权值是可以拿到的,z是另外一个以u为根结点权值最大or次大的点:dp[u][0]+a[y]+dp[z][0]-(dp[z][1]-a[z]),减去的那一部分是dp[u][0]包含的重复的部分。
    此外还需对t为3的情况分两种情况讨论下。

    #include 
    #define int long long
    #define endl '\n'
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int inf=1e18;
    const int N=7e5+5;
    int n,a[N],t[N],dp[N][2],p[N];
    vector<int>e[N];
    //dp[u][0]表示不取以u为根的孩子的最大点数
    //dp[u][1]表示取以u为根获得的最大点数
    void dfs(int u,int fa)
    {
        dp[u][1]=dp[u][0]=a[u];
        int mx1=-inf,mx2=-inf;
        for(int v:e[u])
        {
            if(v==fa) continue;
            dfs(v,u);
            dp[u][0]+=dp[v][1]-a[v];
            int tmp=dp[v][0]-dp[v][1]+a[v];
            if(tmp>mx1) mx2=mx1,mx1=tmp;     //最大值
            else if(tmp>mx2) mx2=tmp;       //次大值
        }
        for(int v:e[u])
        {
            if(v==fa) continue;
            dp[u][1]=max(dp[u][1],dp[u][0]+a[v]);
            if(t[v]==3)
            {
                if(dp[v][0]-dp[v][1]+a[v]==mx1)
                    dp[u][1]=max(dp[u][1],dp[u][0]+mx2+a[v]);
                else
                    dp[u][1]=max(dp[u][1],dp[u][0]+mx1+a[v]);
            }
        }
    }
    void solve()
    {
        cin>>n;
        for(int i=1;i<=n;i++) e[i].clear(),dp[i][0]=dp[i][1]=0;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) cin>>t[i];
        for(int i=1;i<n;i++)
        {
            int u,v;cin>>u>>v;
            e[u].push_back(v);
            e[v].push_back(u);
        }
        dfs(1,0);
        cout<<dp[1][1]<<endl;
    }
    signed main()
    {
        ios;
        int T;cin>>T;
        while(T--)
            solve();
        return 0;
    }
    
    

    C. Klee in Solitary Confinement

    思路:
    1.统计各个数在不同位置上出现次数的前缀和。对于x来说,它可由x和x-k得到,而一个区间内的众数可通过枚举不同的区间得到。
    2.sum[i][0]表示该数字x在下标i出现了几次,sum[i][1]表示该数字x-k在下标i时出现了几次
    公式:sum[e[i].size()][0]+sum[r][1]-sum[l-1][1]-(sum[r][0]-sum[l-1][0])
    化简
    得到:sum[e[i].size()][0]+sum[r][1]-sum[r][0]+sum[l-1][0]-sum[l-1][1]

    #include 
    //#define int long long
    #define endl '\n'
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int inf=1e18;
    const int N=1e6+5;
    int n,k,a[N],sum[N*4][2],mx,g,ans;
    vector<int>e[N*4];
    
    void solve()
    {
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];a[i]+=2e6;
            e[a[i]].push_back(a[i]);
            e[a[i]+k].push_back(a[i]);
            g=max(g,a[i]+k);
            mx=max({mx,(int)e[a[i]].size(),(int)e[a[i]+k].size()});
        }
        if(!k)
        {
            cout<<mx/2<<endl;return;
        }
        for(int i=0;i<=g;i++)
        {
            if(e[i].size()==0) continue;
            for(int j=0;j<e[i].size();j++)
            {
                sum[j+1][0]=sum[j][0]+(e[i][j]==i);
                sum[j+1][1]=sum[j][1]+(e[i][j]!=i);
            }
            int tmp=sum[1][0]-sum[1][1];
            for(int j=1;j<=e[i].size();j++)
            {
                tmp=max(tmp,sum[j-1][0]-sum[j-1][1]);
                ans=max(ans,sum[e[i].size()][0]+sum[j][1]-sum[j][0]+tmp);
            }
        }
        cout<<ans<<endl;
    }
    signed main()
    {
        ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    

    D Strange_Fractions

    注意开根号后的值为正数,并且要保证方程有解。

    #include
    #define int long long
    //#define ll long long
    #define endl '\n'
    #define For(i,a,b) for(i=(a);i<=(b);++i)
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    #define down 0.996
    using namespace std;
    const int N=2e6+5;
    const int inf=1e18;
    const int mod=1e9+7;
    int p,q,a,b;
    
    void solve()
    {
        cin>>p>>q;
        int gcd=__gcd(p,q);
        p=p/gcd;
        q=q/gcd;
        int g=sqrt(p+2*q);
        if(g*g!=p+2*q)
        {
            cout<<0<<" "<<0<<endl;return;
        }
        int tmp=g*g-4*q;
        if(tmp<0)
        {
            cout<<0<<" "<<0<<endl;return;
        }
        int p=sqrt(tmp);
        if(p*p!=tmp)
        {
            cout<<0<<" "<<0<<endl;return;
        }
        int x1=g-p,x2=g+p;
        if(x1%2==0&&x1>=1)
        {
            cout<<x1/2<<" "<<g-x1/2<<endl;
        }
        else if(x2%2==0&&x2>=1)
        {
            cout<<x2/2<<" "<<g-x2/2<<endl;
        }
        else
            cout<<0<<" "<<0<<endl;
    }
    signed main()
    {
        //ios;
        int T;cin>>T;
        while(T--)
            solve();
        return 0;
    }
    
    

    Edge Groups

    思路:
    1.若子树结点v连接有奇数条边,则需要占用连接u的一条边;
    2.若为偶数条边,则每次从n条边中选取两条边,则会有n/2个配对,会产生(n/2)!的重复。其实列举出2、4、6……的情况后不难看出,方案数为小于等于n的奇数相乘。
    3.子树结点边的选取情况可能会占用上一层偶数结点层的结点,需要统计的是可以对父节点产生贡献的可分配的边

    #include 
    #define int long long
    #define endl '\n'
    #define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
    using namespace std;
    const int inf=1e18;
    const int N=1e6+5;
    const int mod=998244353;
    int n,a[N],dp[N];
    vector<int>e[N];
    int dfs(int u,int fa)
    {
        dp[u]=1;
        int cnt=0;
        for(int v:e[u])
        {
            if(v==fa) continue;
            if(!dfs(v,u)) cnt++;
            dp[u]=dp[u]*dp[v]%mod;
        }
        for(int i=1;i<=cnt;i+=2) dp[u]=dp[u]*i%mod;
        return cnt&1;
    }
    void solve()
    {
        cin>>n;
        for(int i=1;i<n;i++)
        {
            int u,v;cin>>u>>v;
            e[u].push_back(v);
            e[v].push_back(u);
        }
        dfs(1,0);
        cout<<dp[1]<<endl;
    }
    signed main()
    {
        //ios;
        //int T;cin>>T;
        //while(T--)
            solve();
        return 0;
    }
    
    
  • 相关阅读:
    前端新手Vue3+Vite+Ts+Pinia+Sass项目指北系列文章 —— 第六章 样式格式化 (Sass配置)
    【ubuntu离线安装docker】
    Bert不完全手册1. Bert推理太慢?模型蒸馏
    安果清理大师-不用的时候我真的不给你推荐这种软件
    使用Puppeteer爬取地图上的用户评价和评论
    自制Linux功能板-新增功能(基于RTMP流媒体传输协议的视频监控)
    Golang优雅之道
    PyTorch搭建AlexNet网络模型
    短视频seo抖音矩阵源码开发搭建技术解析
    1996-2023年各省农林牧渔总产值及农业、林业、牧业、渔业总产值数据(无缺失)
  • 原文地址:https://blog.csdn.net/weixin_51934288/article/details/127087648