牛客练习赛15-C:吉姆的奇思妙想(三分)

链接:https://www.nowcoder.com/acm/contest/83/C

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

吉姆是个热爱算法竞赛的小朋友,平常的休闲活动就是刷 牛客网 的题目。
当吉姆刷到 wannafly挑战赛12 F.小H和圣诞树  这题时,颇为震惊,因为这是他第一次在wannafly挑战赛上看到作者提供的解答的时间复杂度的式子里含有根号的题目,于是吉姆就开始在网络上搜寻拥有类似时间复杂度解法的问题,并且看到了以下这题:
给你一个有 N 个点 M 条边的无向简单图,请算算此图中有几个三角形。我们称无序的三个点 x,y,z 为三角形,若且唯若 (x,y)、(y,z)、(x,z) 都是此图上的边。
吉姆 想了这个问题七天七夜后,他发现了一件事情:
(1) 对于任一个度数为 d 的点,我们可以用 O(d 2) 的时间复杂度来计算有多少三角形包含这该点。
吉姆 又想了这个问题七天七夜后,他又发现了一件事情:
(2) 对于任一个点,我们可以用 O(M) 的时间复杂度来计算有多少三角形包含该点。
吉姆又再想了这个问题十四天十四夜后,他忽然想到:
(3) 不如就把 (1) 和 (2) 的算法结合在一起!找一个恰当的整数s 若一个点度数小于等于s,就使用(1),否则就使用(2),经过缜密的时间复杂度分析,发现这么做的时间复杂度会是 ,取 ,时间复杂度就会是 。最后再把包含各个点的三角形数全部加起来再除以 3 就是答案了! (因为每个三角形会被算到三次。) (此时间复杂度的详细证明会在今天的题解中解说唷~)
但这个 s 的值究竟要设为多少呢?这就和 (1) 与 (2) 两种方法的执行时间的常系数有关了。
于是,吉姆为了透彻了解这个问题,就假定(1) 和(2) 的常系数分别是a 与b,这意思是:对于一个度数为d 的点,若使用(1),程式的执行时间和a×d 2 成正比;若使用(2),程式的执行时间则和b×M 成正比。
对于一个给定的图,吉姆想要知道对于不同的 a,b,s 的值要取多少比较好,并且求出 s 为该值时程式所需的执行时间!
在这个问题里,我们不会真的给你一个图,只会告诉你边数 M。并对于所有正整数 d,告诉你度数为 d 的点有几个。甚至,题目里给你的图不一定实际上存在的简单图(意即输入可能不是一个合法的简单图的度序列)。
大家好,以上是题目背景。(哈哈哈哈哈嚯嚯嚯嚯~)
给你两个正整数 M, L, 以及两个长度为 L 个正整数序列 deg 1,deg 2,..., deg L 和 freq 1, freq 2,..., freq L
(deg i 和 freq i 对应到 Background 里提到的问题的意思就是:度数为 deg i 的点 有 freq i 个。)
你要回答 Q 个问题,第 i 个问题会给你 2 个正整数 a i, b i,请找到一个整数 s 使得以下式子(E i) 的值最小:
(此式就是 Background 里提到的程式执行时间的估计函数)

输入描述:

 
   

输入共有 1+L+1+Q 行。第一行有有两个正整数 M,L。接下来的 L 行中的第 i 行有两个正整数 degi 和 freqi。下一行有一个正整数 Q。最后 Q 行中的第 i 行有两个正整数 ai, bi

输出描述:

对于每个询问都输出一行包含一个整数,代表式子 Ei 的最小值。
示例1

输入

5 4
1 1
2 1
3 1
4 1
5
1 1
3 2
2000 1
1 2000
2000 2000

输出

15
33
20
30
30000

说明

取 s=2 将會有 E1 的最小值:12×1+22×1+5×1+5×1=15。

备注:

1≤M≤10101≤L≤2×1051≤degi,freqi≤10101≤Q≤5×104,1≤ai,bi≤2×103,对于所有 1≤iii+1
对于所有可能测试数据的答案都能使用 64 bit 有符号整数表示。

思路:分析E的那个式子,可以发现随着s的变化,E要么单调,要么先递减后递增。于是可以用三分,还要预处理一下。不过中途会爆long long,然后调试1个多小时,还是WA,果然还是太菜。没办法只有用JAVA写了。

import java.util.*;
import java.math.*;
public class Main {
    static BigInteger pre[]=new BigInteger[200010];
    static BigInteger suf[]=new BigInteger[200010];
    static BigInteger A[]=new BigInteger[200010];
    static BigInteger B[]=new BigInteger[200010];
    static int n;
    public static BigInteger check(int dx,BigInteger a,BigInteger b)
    {
        return a.multiply(pre[dx]).add(b.multiply(suf[dx+1]));
    }
    public static void main(String args[])
    {
        Scanner cin=new Scanner(System.in);
        BigInteger M=cin.nextBigInteger();
        n=cin.nextInt();
        for(int i=1;i<=n;i++)
        {
            A[i]=cin.nextBigInteger();
            B[i]=cin.nextBigInteger();
        }
        pre[0]=BigInteger.ZERO;
        suf[n+1]=BigInteger.ZERO;
        for(int i=1;i<=n;i++)
        {
            pre[i]=A[i].multiply(A[i].multiply(B[i]));
            if(i>1)pre[i]=pre[i].add(pre[i-1]);
        }
        for(int i=n;i>=1;i--)
        {
            suf[i]=M.multiply(B[i]);
            if(i0)
        {
            BigInteger a=cin.nextBigInteger();
            BigInteger b=cin.nextBigInteger();
            int l=0,r=n;
            while(r-1>l)
            {
                int m=(l+r)/2;
                int mm=(m+r)/2;
                if(check(mm,a,b).compareTo(check(m,a,b))<0)l=m;
                else r=mm;
            }
            BigInteger ans=check(l,a,b);
            for(int i=l-4;i<=l+4;i++)if(i>=0&&i<=n&&ans.compareTo(check(i,a,b))>0)ans=check(i,a,b);
            System.out.println(ans);
        }
    }
}


你可能感兴趣的:(思维)