zoukankan      html  css  js  c++  java
  • 二分题集

    「一本通 1.2 练习 2」扩散

    显然联通块的个数是随时间越来越少的。

    所以可以二分时间。

    经过一波运算,可以得出两点需要联通的时间是

    (abs(x[i] - x[j]) + abs(y[i] - y[j]) + 1) / 2

    然后每次用并查集维护一下联通分块就好了。

    第一次写这种开结构体的并查集,感觉很酷炫。

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 60;
    int dis[MAXN][MAXN], x[MAXN], y[MAXN];
    int maxt, n;
    
    struct Disjoint_Set
    {
    	int f[MAXN], sum;
    	void init() 
    	{ 
    		_for(i, 1, n) f[i] = i; 
    		sum = n;
    	}
    	
    	int find(int x)
    	{
    		if(f[x] != x)
    			f[x] = find(f[x]);
    		return f[x];
    	}
    	
    	void Union(int a, int b) 
    	{ 
    		int aa = find(a), bb = find(b);
    		if(aa != bb)
    		{
    			f[aa] = bb;
    			sum--;
    		}
    	}
    }S;
    
    bool check(int t)
    {
    	S.init();
    	_for(i, 1, n)
    		_for(j, i + 1, n)
    			if(dis[i][j] <= t)
    				S.Union(i, j);
    	return S.sum == 1;
    }
     
    int main()
    {
    	scanf("%d", &n);
    	_for(i, 1, n) scanf("%d%d", &x[i], &y[i]);
    	_for(i, 1, n)
    		_for(j, i + 1, n)
    		{
    			int d = (abs(x[i] - x[j]) + abs(y[i] - y[j]) + 1) / 2;
    			dis[i][j] = dis[j][i] = d;
    			maxt = max(maxt, d);
    		}
    	
    	int l = -1, r = maxt;
    	while(l + 1 < r)
    	{
    		int m = (l + r) >> 1;
    		if(check(m)) r = m;
    		else l = m;
    	} 
    	printf("%d
    ", r);
    	
        return 0;
    }

    poj 2018

    这道题是一道好题。

    首先可以二分平均数,把最优问题转化成判定性问题

    然后可以预处理,把每个数减去平均数,只要最终的结果大于等于0就可以了,这个很秀。

    最后要解决一个问题,求一个子序列,它的和最大,子序列的程度不小于L

    我们可以枚举终点i,然后就转化成0 <= j <= i - L中 最小的[j, i - L]

    每次枚举的时候j的范围只会加1,所以我们可以直接在枚举的时候更新答案。

    注意最后输出要转化一下类型。

    #include<cstdio>
    #include<algorithm>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 1e5 + 10;
    double a[MAXN], s[MAXN]; 
    int n, L;
    
    bool check(double m)
    {	
    	_for(i, 1, n)  s[i] = s[i - 1] + a[i] - m;
    	double ans = -1e12, min_val = 1e12;	
    	_for(i, L, n)
    	{
    		min_val = min(min_val, s[i - L]);
    		ans = max(ans, s[i] - min_val);
    	}
    	return ans >= 0;
    }
    
    int main()
    {
    	scanf("%d%d", &n, &L);
    	_for(i, 1, n) scanf("%lf", &a[i]); 
    	
    	double l = -2001, r = 2001;
    	while(r - l > 1e-8)
    	{
    		double m = (l + r) / 2;
    		if(check(m)) l = m;
    		else r = m;
    	}
    	printf("%d
    ", int(r * 1000));
    	
    	return 0;
    }
  • 相关阅读:
    逆波兰表达式解数学运算(c#)
    杂文
    WebDriverExtensionsByC#
    cookie使用
    Discuz
    重构中学习
    生活知识
    js和 jquery对象
    jquery中is的用法
    html下select追加元素,IE下错误
  • 原文地址:https://www.cnblogs.com/sugewud/p/9819303.html
Copyright © 2011-2022 走看看