• Codeforces Round #576 (Div. 2) 题解


    比赛链接https://codeforc.es/contest/1199
     
    A. City Day
    题意:给出一个数列,和俩个整数(x,y),要求找到序号最靠前的数字(d),使得(d)满足(a_d<a_j) ((d-xleq j<d) && (d<jleq d+y))。

    分析:由于x和y都小于7,所以直接暴力即可。

    AC代码:

    #include <bits/stdc++.h>
    #define SIZE 200007
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    using namespace std;
    typedef	long long ll;
    void io() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    }
    ll n, x, y, a[SIZE];
    int main() {
    	io();
    	cin >> n >> x >> y;
    	rep(i, 1, n) cin >> a[i];
    	rep(i, 1, n) {
    		bool flag = 1;
    		for (int k = i - 1, cnt = 1; k > 0 && cnt <= x; k--, cnt++) {
    			if (a[k] <= a[i]) { flag = 0; break; }
    		}
    		for (int k = i + 1, cnt = 1; k <= n && cnt <= y; k++, cnt++) {
    			if (a[k] <= a[i]) { flag = 0; break; }
    		}
    		if (flag) { cout << i << endl; return 0; }
    	}
    }
    

     
    B. Water Lily

    分析:几何水题,推个方程就好。

    AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
    	double l, h;
    	cin >> h >> l;
    	double s = (l * l - h * h) / 2 / h;;
    	printf("%.12lf", s);
    }
    

     
    C. MP3
    题意:一个数组中如果有(K)种不同的数,每个数的占用空间是(k=log_2K),这组数总内存是(nk),你有一个改变数的大小的能力,小于(l)可以改成(l)大于(r)可以改成(r),现在给出总内存,求最少改变次数。

    分析:先求出最多能存(k)个数,然后我们显然用(map)来记录数据,然后把(map)中的前(k)个数和后k个数丢进一个双向队列(因为我们至少删除(k)个数,而这(k)个数只能在首或尾),对这(2k)个数求前缀和,在每k个数中求出最小值。

    AC代码:

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define SIZE 400007
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    using namespace std;
    typedef	long long ll;
    void io() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    }
    ll n, I, a[SIZE], pre[SIZE];
    map<ll, ll> mp;
    deque<pair<ll, ll> > q;
    int main() {
    	io(); cin >> n >> I;
    	rep(i, 1, n) {
    		cin >> a[i];
    		++mp[a[i]];
    	}
    	ll k = 0; I *= 8;   //用k记录最多存储几个数
    	while (1ll * ceil(log2(mp.size() - k))* n > I) k++;
    	auto it = mp.begin();
    	auto itr = mp.rbegin();
    	rep(i, 1, k) {
    		q.push_back(make_pair(it->first, it->second));
    		q.push_front(make_pair(itr->first, itr->second));
    		it++, itr++;
    	}
    	auto itx = q.begin();
    	rep(i, 1, q.size()) pre[i] = pre[i - 1] + itx++->second;
    	ll sum = INF;
    	rep(i, k, 2 * k) sum = min(sum, pre[i] - pre[i - k]);
    	cout << sum;
    }
    

     
    D. Welfare State
    题意:给定一个(n)个数的数列和两种操作。操作一是把序号为(p)的数字修改为(x),操作二是把所有小于(x)的数字修改为(x)。输出最终的数列。

    分析:乍一看像线段树,但是写得不好就会(T)(别问我怎么知道的),实际上直接乱搞就过了。我们发现对于第一种操作和第二种操作我们只需要考虑较大的那种,因此开两个数组,(b)数组保存操作一,(maxx)数组保存操作二,最后取(max)输出即可。

    AC代码:

    #include<bits/stdc++.h>
    #define SIZE 200007
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    using namespace std;
    typedef	long long ll;
    void io() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    }
    ll n, m, a[SIZE], b[SIZE], sig, maxx[SIZE], pos;
    int main() {
    	io(); cin >> n;
    	rep(i, 1, n) cin >> a[i];
    	cin >> m;
    	rep(i, 1, m) {
    		cin >> sig;
    		if (sig == 1) {
    			cin >> pos;
    			cin >> a[pos];
    			b[pos] = i;
    		}
    		else cin >> maxx[i];
    	}
    	for (int i = m; i; --i) maxx[i - 1] = max(maxx[i - 1], maxx[i]);
    	rep(i, 1, n) cout << max(a[i], maxx[b[i]]) << ' ';
    }
    

     
    E. Matching vs Independent Set
    题意:给定一个(3n)个顶点,(m)条边的图和两个定义。定义一:如果一个边集中没有两条边共享一个端点,则称为匹配。定义二:如果一个点集中没有两个顶点与边连接,则一组顶点称为独立集。判断给定的图是否存在匹配或独立集((size=n))。

    分析:乍看像一道图论,实际上并不需要图论算法。首先用vector存图。然后观察到匹配和独立集必定至少存在一个。证明:我们考虑每次取(n)个点,若不存在独立集,则这(n)个点中至少存在一条边,这样操作到最后至多存在(n-2)个点不连边,且不存在独立集;但是这样的构造后我们发现,在那(2n+2)个点中至少存在(n+1)条边构成匹配。因此,我们只需要处理出所有独立的点,判断是否能构成独立集,若不能则至少有(2n+2)个点有连边,我们两两取边加入匹配集并输出即可。

    AC代码:

    #include <bits/stdc++.h>
    #define SIZE 500007
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    using namespace std;
    typedef	long long ll;
    void io() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    }
    typedef long long ll;
    vector <pair<int, int> > h[SIZE];
    vector <int> edge, vec;
    int n, m, T, cnt, u, v;
    bool vis[SIZE];
    int main() {
    	io(); cin >> T;
    	while (T--) {
    		cin >> n >> m;
    		edge.clear(); vec.clear(); cnt = 0;
    		rep(i, 1, 3 * n) { h[i].clear(); vis[i] = false; }
    		rep(i, 1, m) {
    			cin >> u >> v;
    			h[u].emplace_back(make_pair(v, i));
    			h[v].emplace_back(make_pair(u, i));
    		}
    		rep(i, 1, 3 * n) {
    			bool flag = false;
    			for (auto it : h[i]) {
    				int pos = it.first;
    				if (vis[pos]) {
    					flag = true; vis[pos] = false;
    					edge.emplace_back(it.second);
    					break;
    				}
    			}
    			if (!flag) vis[i] = true, cnt++;
    			else cnt--;
    		}
    		if (cnt >= n) {
    			cout << "IndSet" << endl;
    			int num = 0;
    			rep(i, 1, 3 * n) {
    				if (num >= n) break;
    				if (vis[i]) { num++; cout << i << ' '; }
    			}
    		}
    		else {
    			cout << "Matching" << endl;
    			rep(i, 0, n - 1) cout << edge[i] << ' ';
    		}
    		cout << endl;
    	}
    }
    

     
    F. Rectangle Painting 1
    题意:给定一个(n imes n)的方格网。每次能在图中选择一个(a imes b)的矩形,将该矩形中的方格全部改为“.”,一次操作的花费为(max(a,b))。要求把“#”全部改成“.”,求最小的花费。

    分析:由于(nleq 50),所以我们考虑直接暴力四重dp。用(f[x][y])记录((1,1))((x,y))的“#”数量,用(dp[x][y][i][j])记录((x,y))((i,j))之间全部染成“.”的花费,然后转移即可。

    AC代码:

    #include <bits/stdc++.h>
    #define SIZE 55
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    using namespace std;
    typedef	long long ll;
    void io() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    }
    int n;
    char s[SIZE][SIZE];
    int dp[SIZE][SIZE][SIZE][SIZE];
    int f[SIZE][SIZE];
    int main() {
    	io(); cin >> n;
    	rep(i, 1, n) {
    		cin >> (s[i] + 1);
    	}
    	rep(i, 1, n) {
    		rep(j, 1, n) {
    			f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1] + (s[i][j] == '#');
    		}
    	}
    	rep(x, 1, n) {
    		rep(y, 1, n) {
    			rep(i, 1, n - x + 1) {
    				rep(j, 1, n - y + 1) {
    					int tx = i + x - 1, ty = j + y - 1;
    					int t = f[tx][ty] - f[i - 1][ty] - f[tx][j - 1] + f[i - 1][j - 1];
    					if (!t) { dp[i][j][tx][ty] = 0; continue; }
    					else dp[i][j][tx][ty] = max(x, y);
    					rep(k, i + 1, tx) {
    						dp[i][j][tx][ty] = min(dp[i][j][tx][ty], dp[i][j][k - 1][ty] + dp[k][j][tx][ty]);
    					}
    					rep(k, j + 1, ty) {
    						dp[i][j][tx][ty] = min(dp[i][j][tx][ty], dp[i][j][tx][k - 1] + dp[i][k][tx][ty]);
    					}
    				}
    			}
    		}
    	}
    	cout << dp[1][1][n][n];
    }
    
  • 相关阅读:
    JavaScript快速入门-ECMAScript本地对象(String)
    JavaScript快速入门-ECMAScript语句
    Zabbix实战-简易教程--业务类
    [转] STL源码学习----lower_bound和upper_bound算法
    [转] C++中临时对象及返回值优化
    二叉堆,优先队列,二叉树的理解
    [转] GCC __builtin_expect的作用
    [转] __thread关键字
    C++初始化顺序
    [转] shared_from_this 几个值得注意的地方
  • 原文地址:https://www.cnblogs.com/st1vdy/p/11273191.html
Copyright © 2020-2023  润新知