• [EOJ Monthly2019.11][T4]安全带


    以下是题干

    D. 安全带

    单点时限: 1.0 sec 内存限制: 256 MB

    (前面题干是一堆废话,我把它删了)
    简单来说:初始给出一个 n 个点顺次连接而成的环,点有点权,边权是两个端点的点权乘积。现在给出一些特殊点,这些特殊点是向其他所有点都有连边,如果连边时发现两点之间已经有边,不会再次连接(即图中不会有重边)。求图中边权和。

    输入格式

    输入第一行包含一个整数 n(3≤n≤105) ,表示按钮数量。

    第二行包含 n 个用空格隔开的整数 a1,a2,⋯,an(1≤ai≤104) ,分别表示按钮的权值。

    第三行包含 n 个用空格隔开的整数 b1,b2,⋯,bn(bi∈{0,1}) ,分别表示按钮的开关状态。其中 bi=1 表示第 i 个按钮按下了,bi=0 表示第 i 个按钮没有被按下。

    输出格式

    输出一个整数,表示安全带的松紧程度。

    样例输入1

    3
    2 3 3
    1 0 1
    

    样例输出1

    21
    

    样例输入2

    3
    2 3 3
    0 0 0
    

    样例输出2

    21
    

    提示

    第一个样例解释:

    初始的时候图中有三条边 (1,2),(2,3),(3,1) ,边权分别是 6,9,6 。

    点 1 和点 3 向其他所有点有边,而这些边均已存在在图中,故不重复连接,所以边权和为 6+9+6=21 。

    Solution

    正难则反。如果按顺序,先把编号相邻的点连接起来,再处理按钮的连接,肯定是不好处理的。观察发现这两个步骤其实不是冲突的。我们考虑先把按了的按钮处理出来,然后看看哪些相邻点还没有,再加上来就行了。这道题比较有技巧性的地方就是要维护一个特殊的变量。刚开始按第一个按钮的时候,所有点都不是连接的,那么我们可以用所有其他点的权值和✖️该点权值求出我们的边权和。当按过多个按钮后,因为这些按钮和所有的其他点都连接了,按过的按钮的权值日后不会再有任何贡献,因此我们把的权值他们用一个变量累计起来,在之后算没有连接过的点权和的时候,没有连接过的点权和=点权和-该点的权-按过的按钮的权的累计。这样就可以用O(N)的复杂度完成这道题

    /*
     * Created by AronQi
     * For personal training
     * 2019/09/28
    */
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define RG register
    
    using namespace std;
    
    template<class Type> inline void R(Type &x)
    {
        RG int c=getchar();for(;c<48||c>57;c=getchar());
        for(x=0;c>47&&c<58;x=x*(Type)10+c-48,c=getchar());
    }
    
    int N,a[100001];
    bool f[100001];
    long long ans=0,sum[100001],tot=0;
    
    int main()
    {
        R(N);
        for(RG int i=1;i<=N;++i)
        {
            R(a[i]);
            tot+=a[i];
        }
        for(RG int i=1;i<=N;++i)
            sum[i]+=tot-a[i];
        tot=0;
        for(RG int i=1;i<=N;++i)
        {
            R(f[i]);
            if(f[i]==1)
            {
                ans+=(long long)a[i]*(sum[i]-tot);
                tot+=a[i];
            }
        }
        for(RG int i=1;i<=N;++i)
        {
            if(f[i]==1)continue;
            if(f[(i%N)+1]==0)
                ans+=a[i]*a[(i%N)+1];
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    System.currentTimeMillis();
    java中synchronized使用方法
    距离矢量路由协议举例——RIP
    Bulk Insert命令具体
    美国地名大全(美国城市名称英文、中文)
    面试准备系列01----面试中的链表题目汇总
    Introspector(内省)简单演示样例 与 简单应用
    Android APK反编译具体解释(附图)
    MATLAB新手教程
    Nginx+Tomcat7+Mencached负载均衡集群部署笔记
  • 原文地址:https://www.cnblogs.com/keshuqi/p/11960830.html
Copyright © 2020-2023  润新知