EOJ:3735. 安全带

单点时限: 1.0 sec

内存限制: 256 MB

“叮------“平稳了没多久,安全带的指示灯又亮了。

“飞机遇到气流正在颠簸,请系好安全带” 不知道已经是第几次语音播报了,毫无意外,飞机再次开始失重下降。

Cuber QQ 的座位是在高贵的特等舱。飞机再次失重的时候,Cuber QQ 开始观察起了座位上的安全带。

特等舱的安全带自然是十分高级的。他由 n 个按钮构成,每个按钮之间均可以通过特质的材料绳连接。为了保证基本的安全,
安全带初始的 n 个按钮顺次连接。具体来说,每个按钮都有一个编号,分别是 1 到 n ,
初始的时候安全带包含了 n 条已经连接的特质的材料绳,他们分别连接按钮 1 和 按钮2 、 按钮 2 和 按钮3 、 ⋯ 、按钮 n−1 
和 按钮n 、按钮 n 和 按钮1 。

为了满足不同旅客的不同需求,安全带还可以由旅客自己来调节松紧。
具体来说,旅客可以选择按下某一些按钮,一旦这个按钮被按下,从这个按钮出发会通过特质的材料绳连接其他所有的按钮
(如果这两个按钮之间已经有连接了,不会发生第二次连接)。

Cuber QQ 为了更加方便的定义安全带的松紧,他给每一个按钮定义了一个权值,而一条特质的材料绳的松紧程度定义为他所连接两个按钮权值的乘积。
一个安全带的松紧程度,定义为所有连接的特质的材料绳的松紧程度之和。

现在 Cuber QQ 会告诉你他给安全带按钮定义的权值和按下的按钮,他想知道安全带现在的松紧程度。

简单来说:初始给出一个 n 个点顺次连接而成的环,点有点权,边权是两个端点的点权乘积。
现在给出一些特殊点,这些特殊点是向其他所有点都有连边,如果连边时发现两点之间已经有边,不会再次连接(即图中不会有重边)。求图中边权和。
输入格式

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

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

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

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

———————————————————————————————————————————————————
题目长的一批,还好下面有个 “简单来说”。。。

分析数据量:数据规模达到了10的5次方,远超暴力解法的上限2500

思路及代码:

理解题目后,其实就是每个按键有一个权值和一个状态

typedef struct{
	int weight;
	bool stat;
}button; 

录入数据:

int n = 0;
int tmp = 0;
long long sum = 0;
long long sumWeight = 0;
while(EOF!=scanf("%d",&n))
{
    sumWeight = 0;
    sum = 0;
    button* pbuttons = (button *)calloc(sizeof(button),n);
    for(int i = 0;i<n;++i)
    {
        scanf("%d",&(pbuttons[i].weight));
        sumWeight+=pbuttons[i].weight;
    }
    for(int i = 0;i<n;++i)
    {
        scanf("%d",&tmp);
        if(tmp)
            pbuttons[i].stat = true;
        else
            pbuttons[i].stat = false;
    }
//未完

若状态为按下(curButton.stat == true),则把他的权值和其他每个按键的权值依次相乘求和。
注意这里不需要再一次遍历每个按键,乘法分配律,只需提前求出所有按键权值总和:sumWeight,每次用当前curButton.weight *(sumWeight - curButton.weight)即可;
另外考虑 不重复计算 的问题,每当检测出按键状态为true,上面的计算会使得他和其他所有节点完成相关的计算,即整个问题中与他相关的权值计算已经结束了,就可以把他从sumWeight里剔除:sumWeight -= curButton.weight。
最后考虑 相邻按钮 的计算问题,每个相邻按键之间默认存在链接,这里在上述步骤的计算中,已经把所有stat == true 的按键的相邻按键计算过了,因此只需计算相邻两个节点都stat == false的即可,这里让每个节点向前检查(类似于一个环,每个节点负责自己左边一个)。

//接上
    for(int i = 0;i<n;++i)
    {
        if(pbuttons[i].stat)//处理按下的按键
        {
            sum += pbuttons[i].weight*(sumWeight - pbuttons[i].weight);
            sumWeight -= pbuttons[i].weight;
        }
        else//处理没按下的按键
        {
            if(!pbuttons[ (i - 1 + n)%n].stat)
                sum += pbuttons[(i - 1 + n)%n].weight * pbuttons[i].weight;
        }
    }

    free(pbuttons);
    printf("%lld",sum);
}

这样,O(n)的复杂度即可解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值