Codeforces 818F Level Generation(三分)

4 篇文章 0 订阅
2 篇文章 0 订阅

F. Level Generation
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Ivan is developing his own computer game. Now he tries to create some levels for his game. But firstly for each level he needs to draw a graph representing the structure of the level.

Ivan decided that there should be exactly ni vertices in the graph representing level i, and the edges have to be bidirectional. When constructing the graph, Ivan is interested in special edges called bridges. An edge between two vertices u and v is called a bridge if this edge belongs to every path between u and v (and these vertices will belong to different connected components if we delete this edge). For each level Ivan wants to construct a graph where at least half of the edges are bridges. He also wants to maximize the number of edges in each constructed graph.

So the task Ivan gave you is: given q numbers n1, n2, …, nq, for each i tell the maximum number of edges in a graph with ni vertices, if at least half of the edges are bridges. Note that the graphs cannot contain multiple edges or self-loops.

Input
The first line of input file contains a positive integer q (1 ≤ q ≤ 100 000) — the number of graphs Ivan needs to construct.

Then q lines follow, i-th line contains one positive integer ni (1 ≤ ni ≤ 2·109) — the number of vertices in i-th graph.

Note that in hacks you have to use q = 1.

Output
Output q numbers, i-th of them must be equal to the maximum number of edges in i-th graph.

Example
input
3
3
4
6
output
2
3
6
Note
In the first example it is possible to construct these graphs:

1 - 2, 1 - 3;
1 - 2, 1 - 3, 2 - 4;
1 - 2, 1 - 3, 2 - 3, 1 - 4, 2 - 5, 3 - 6.

题目大意:

  告诉你结点数,让你构造一张图,其中桥至少要占边数的一半,问最多能够有多少条边。

解题思路:

  我们可以先取 x 个点形成一个完全子图,剩下的连成一条链,并和这个子图连接上,这样链中的边全部都是桥。完全子图中有x(x1)2条边,链上有 Vx 条边。由于题目要求桥至少要占边数的一半,所以完全子图中保留 min(x(x1)2,Vx) 条边,最终对于取 x 个点形成完全子图的情况最多有f(x)=min(x(x1)2,Vx)+Vx条边。很明显 f(x) 是凸函数,我们可以三分得到答案。

AC代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))
#define sqr(x) ((x)*(x))

LL N;

inline LL judge(const LL &x)
{
    return min(N-x, x*(x-1)/2)+N-x;
}

int main()
{
    int T_T;
    scanf("%d", &T_T);
    while(T_T--)
    {
        scanf("%lld", &N);
        LL l=1, r=N;
        while(r-l>2)
        {
            LL mid=(l+r)/2;
            LL midmid=(mid+r)/2;
            if(judge(midmid)>judge(mid))
                l=mid;
            else r=midmid;
        }
        printf("%lld\n", max(judge(l), max(judge(l+1), judge(r))));
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值