【Codeforces Round #353 Div2】个别题的记录
先是Div2的C.Money Transfers:
题意是指 给定N个点围成一个环(意味着1与N点相连接),每个点各有一个权值,每次可以将任意一个点的任意权值移动到左右一个点上,问最短经过多少步能将所有点权值变为0
数据保证所有点权和为0
思路:找出尽可能多的0,使得对整个序列的操作最少,这些0可能是单点可能是段(我们称它为0序列)
对于一个长度为L和为0的段,对它进行全0操作的步数应该是L-1
所以,我们可以记录前缀和A[i] = A[i - 1] + num;
再记录最长能分成的段数maxx[A[i]],这样答案便是:max(maxx[A[1]],maxx[A[2]]...,maxx[A[N]]);
再用n减去max即可。
代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <map> 5 #include <algorithm> 6 #pragma warning(disable:4996) 7 using namespace std; 8 typedef long long LL; 9 const int maxn = 100000 + 10; 10 map<LL, int>maxx; 11 LL a[maxn]; 12 int main(){ 13 LL num; 14 int n; 15 while (~scanf("%d", &n)) { 16 int maxxx = 0; 17 a[0] = 0; 18 maxx.clear(); 19 for (int i = 1; i <= n; ++i) { 20 scanf("%I64d", &num); 21 a[i] = (a[i - 1] + num); 22 maxxx = max(maxxx, ++maxx[a[i]]); 23 } 24 printf("%d\n", n - maxxx); 25 } 26 return 0; 27 }
再是Div2的D.Tree Construction:
题意是依次给出N个数,并按照他的规则建树:
如果当前元素大于前面的某些元素,那么这个元素必须在之前那些元素的右边;同理,小的就在左边
二叉搜索树
问每一个节点的前一个父亲节点是什么
首先就想到了。。当前元素a[i] 的范围 肯定是 :
1.在最前面的某两个数之间
2.小于或大于所有的前面的数
利用set维护这个数组,利用upperbound查找比他大的第一个数,如果找不到,或者已经有左右儿子
那么iter--(显然在两个数之间!!)因为第一个数是根,所以肯定不会出现向下越界的情况
#include <iostream> #include <cstdio> #include <cstring> #include <map> #include <algorithm> #include <set> #pragma warning(disable:4996) using namespace std; typedef long long LL; set<int>tree; map<int, int>lson; map<int, int>rson; const int maxn = 100000 + 10; int n, nd, res[maxn]; void init() { tree.clear(); lson.clear(); rson.clear(); } int main() { while (cin >> n) { init(); cin >> nd; tree.insert(nd); for (int i = 1; i < n; ++i) { cin >> nd; set<int>::iterator noww = tree.upper_bound(nd); if (noww != tree.end() && lson[*noww] == 0) { lson[*noww] = nd; res[i] = *noww; } else { noww--; rson[*noww] = nd; res[i] = *noww; } tree.insert(nd); } for (int i = 1; i < n; ++i) { if (i != 1) cout << " "; cout << res[i]; } cout << endl; } return 0; }

浙公网安备 33010602011771号