• Codeforces Round #722 (Div. 2)


    A

    题目描述

    给定一个数列\(A\),每次选一个子序列算平均值并且删掉比平均值大的元素,问最多删去几个值?

    数据范围

    \(n \leq 100,a_i \leq 100\)

    分析

    最后一定剩一个最小元素,排序输出即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 110;
    
    int a[N];
    
    int main () {
    	int T;
    	cin >> T;
    	while(T --) {
    		int n;
    		int pos = -1;
    		cin >> n;
    		for(int i = 1;i <= n; ++i) cin >> a[i];
    		sort(a + 1,a + n + 1);
    		int tmp = a[1];
    		for(int i = 1;i <= n; ++i) {
    			if(a[i] != tmp) {
    				//cout << "#:" << i << endl;
    				pos = i;
    				break;
    			}
    		}
    		if(pos == -1) cout << 0 << endl;
    		else cout << n - pos + 1 << endl;
    	}
    	return 0;
    }
    

    B

    题目描述

    给定一个数组\(B\),求一个最大集合使得集合中任意一对元素\((u,v)\)满足\(|u - v| >= max_S\)

    数据范围

    \(\sum n \leq 10^5\)

    分析

    将数组从小到大排序,然后记录一个当前集合中的点对元素距离最小值,计算结果输出即可。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 10;
    int T;
    int n;
    int a[N];
    int main () {
    	cin >> T;
    	while(T --) {
    		cin >> n;
    		for(int i = 1;i <= n; ++i) {
    			cin >> a[i];
    		}
    		sort(a + 1,a + n + 1);
    		int ans = 1;
    		int lm = INT_MAX;
    		for(int i = 2;i <= n; ++i) {
    			int tmp = abs(a[i] - a[i - 1]);
    			lm = min(lm,tmp);
    			if(lm < a[i]) break;
    			else ans ++;
    		}
    		cout << ans << endl;
    	}
    	return 0;
    }
    

    C

    题目描述

    给定一个树,每个节点可以选的值为\([l_i,r_i]\)之间的一个值,求如何安排数值可以使得\(\sum_{u,v \in T} |a_u - a_v|\)最大,输出最大值。

    数据范围

    \(\sum n \leq 10^5,T \leq 250,1 \leq l_i,r_i \leq 10^9\)

    分析

    对于任意连接的一个点对\((u,v)\)来说,最大值一定出现在端点处,我们考虑设\(f_{i,0/1}\)表示当处理到第\(i\)个节点时,当前节点选\(l_i\)\(r_i\)的最大收益,转移为:

    f[u][0] += max(f[v][0] + abs(l[u] - l[v]),f[v][1] + abs(l[u] - r[v]));
    f[u][1] += max(f[v][0] + abs(r[u] - l[v]),f[v][1] + abs(r[u] - r[v]));
    

    开个\(long \; \;long\)

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int N = 1e5 + 10;
    ll f[N][2];//选上界,or选下界
    
    struct edge {
    	int to;
    	int nxt;
    }e[N << 1];
    int cnt;
    int head[N];
    void add (int u,int v) {
    	e[++cnt].to = v;
    	e[cnt].nxt = head[u];
    	head[u] = cnt;
    	return;
    }
    
    void Addtree(int u,int v) {
    	add(u,v),add(v,u);
    }
    int T;
    int n;
    int l[N],r[N];
    
    void dfs(int x,int fa) {
    	for(int i = head[x];i;i = e[i].nxt) {
    		int y = e[i].to;//cout << "#:" << y << endl;
    		if(y == fa) continue;
    		dfs(y,x);
    		f[x][0] += max(f[y][0] + abs(l[x] - l[y]),f[y][1] + abs(r[y] - l[x]));
    		f[x][1] += max(f[y][0] + abs(r[x] - l[y]),f[y][1] + abs(r[y] - r[x]));
    	}
    }
    
    
    int main () {
    	ios :: sync_with_stdio(false);
    	cin >> T;
    	while(T --) {
    		cin >> n;
    		for(int i = 1;i <= n; ++i) cin >> l[i] >> r[i];
    		cnt = 0;
    		memset(head,0,sizeof head);
    		memset(f,0,sizeof f);
    		for(int i = 1;i < n; ++i) {
    			int u,v;
    			cin >> u >> v;
    			Addtree(u,v);
    		}
    		dfs(1,0);
    		//cout << "#:" << endl;
    		//for(int i = 1;i <= n; ++i) cout << f[i][0] << ' ' << f[i][1] << endl;
    		cout << max(f[1][0],f[1][1]) << endl;
    	}
    	return 0;
    }
    
    

    D

    题目描述

    给定\(2n\)个点,求可以形成\(n\)个点对使得满足:

    • 大小相同
    • 互相包含

    的方案数。

    数据范围

    \(n \leq 10^6\)

    分析

    这道题还是很考察思维能力的。

    先考虑这个题如何递推下去,对于一种长度为\(2i\)的情况,如果想变成\(2i+2\)的情况,就需要在两边填上两个点,中间变为“包含”情况。

    考虑大小相同的情况如何计算:

    • 因为你需要让\(n\)个点对用恰好\(2n\)个点,考虑枚举长度,经过验算发现,如果说长度为\(i\)的约数,那么必定存在一种大小相同的情况的局面,因此大小相同的情况为\(i\)的约数个数。

    然后再考虑包含情况:

    • 根据递推,当\(i = 0\)的时候是无解的,因此此时答案为0.
    • \(f_i\)表示长度为\(2i\)情况的方案数,那么\(f_i += sum_{c_j}\)\(c为约数\),维护好\(sum\)值即可。
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e6 + 10;
    #define ll long long
    const int mod = 998244353;
    ll f[N];//µÚi¸öµãµÄ½á¹û
    int c[N];
    int n;
    
    void _div(int n) {
    	for(int i = 1;i <= n; ++i) {
    		for(int j = i;j <= n;j += i) {
    			c[j] ++;
    		}
    	}
    }
    int main () {
    	
    	ll n;
    	cin >> n;
    	//vector <int> d;
    	_div(n);
    	ll sum = 0;
    	for(int i = 1;i <= n; ++i) {
    		//cout << v[i].size() << endl;
    		
    		f[i] = (sum + c[i]) % mod;
    		sum = (sum + f[i]) % mod;
    	}	
    	cout << f[n] % mod << endl;
    	return 0;
    }
    

    E

  • 相关阅读:
    [BZOJ2738]矩阵乘法 整体二分+树状数组
    [Tjoi2016&Heoi2016] 序列 CDQ分治
    BZOJ 2716 天使玩偶 CDQ分治
    BZOJ3295 动态逆序对 CDQ/分块+树状数组
    hdu 6851 Vacation(思维+贪心)
    hdu 6579 Operation (在线线性基)
    hdu 6852Path6(最短路+最小割)
    网络最大流之初见
    Codeforces Round #587 C. White Sheet(思维+计算几何)
    VK Cup 2017
  • 原文地址:https://www.cnblogs.com/akoasm/p/14809782.html
Copyright © 2020-2023  润新知