zoukankan      html  css  js  c++  java
  • 1027上午考试总结

    1027上午考试总结

    T1

    ​ 题目大意:

    ​ 有(n)个位置,可以往里面填1到n的数.有(m)个限制条件,形如"[l,r]",表示从l到r放的数都不一样,问如何填数使整个序列字典序最小.(n,m <= 1e5)

    ​ 贪心,构造.

    ​ 首先将区间按左端点排序,某一些区间假设被别的区间完全包含的话,那么他肯定是没有用的,只需要考虑那些大的区间.然后每次往区间里填数都是从左往右1,2,3...这么填,可以保证字典序最小.假如两段区间有重合部分,优先把前一段区间填完后,在"回收"一些数填到下一个区间里,这个过程可以用优先队列搞一搞,我用的是时间戳,可能会被卡把.用了优先队列的话时间复杂度就是(O(n log n)).

    #include <bits/stdc++.h>
    
    using namespace std;
    
    inline long long read() {
    	long long s = 0, f = 1; char ch;
    	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    	return s * f;
    }
    
    const int N = 1e5 + 5;
    int t, n, m;
    int ans[N], vis[N];
    struct line { int l, r; } a[N];
    
    int cmp(line a, line b) {
    	if(a.l == b.l) return a.r > b.r;
    	return a.l < b.l;
    }
    
    int main() {
    	
    	for(t = read(); t ; t --) {
    		n = read(); m = read();
    		for(int i = 1;i <= n; i++) ans[i] = 1, vis[i] = 0;
    		for(int i = 1;i <= m; i++) a[i].l = read(), a[i].r = read();
    		sort(a + 1, a + m + 1, cmp);
    		int now = 0;
    		for(int i = 1;i <= m; i++) {
    			if(now >= a[i].r) continue;
    			int tmp = 1;
    			if(a[i].l >= now + 1) for(int j = a[i].l;j <= a[i].r; j++) ans[j] = tmp ++;
    			else {
    				for(int j = a[i].l;j <= now; j++) vis[ans[j]] = i;
    				for(int j = now + 1;j <= a[i].r; j++) {
    					while(vis[tmp] == i) tmp ++; ans[j] = tmp; vis[tmp] = i;
    				}
    			}
    			now = a[i].r;
    		}
    		for(int i = 1;i <= n; i++) printf("%d%c", ans[i], i == n ? '
    ' : ' ');
    	}
    	
    	return 0;
    }
    

    T2

    ​ 题目大意:

    ​ 有一辆货车,载货量为(m),有(n)个人,每个人有(a[i])重量的物品,现在已经给定这(n)个人的顺序,问对于每个人,在强制放他的物品后,他前面最多有多少人可以放进自己的物品,输出剩下的最少的人数.(n <= 1e5, a <= 1e9)

    ​ 离散化 + 线段树.

    ​ 当强制放了第(i)个人后,货车的剩余容量就是(m - a[i]),现在要找出(i)前面最多能有几个人放进去,肯定是优先放物品重量小的.我们先把所有物品离散化,然后开一颗权值线段树,维护物品的个数和物品的总重量,然后在权值线段树里找个数就好了.当第(i)个人强制放也放不进去时记得特判输出0就好了.

    #include <bits/stdc++.h>
    
    #define ls(o) (o << 1)
    #define rs(o) (o << 1 | 1)
    #define mid ((l + r) >> 1)
    
    using namespace std;
    
    inline long long read() {
    	long long s = 0, f = 1; char ch;
    	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    	for(s = ch ^ 48; isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    	return s * f;
    }
    
    const int N = 1e5 + 5;
    int T, n, m;
    int a[N], b[N];
    struct tree { int num; long long sum; } t[N << 2];
    
    void build(int o, int l, int r) {
    	t[o].num = t[o].sum = 0;
    	if(l == r) return ;
    	build(ls(o), l, mid); build(rs(o), mid + 1, r);
    }
    
    int query(int o, int l, int r, int res) {
    	if(res == 0) return 0;
    	if(l == r) {
    		if(t[o].sum <= res) return t[o].num;
    		else {
    			int num = res / b[l]; return min(num, t[o].num);
    		}
    	}
    	if(t[o].sum <= res) return t[o].num;
    	if(t[ls(o)].sum <= res) return t[ls(o)].num + query(rs(o), mid + 1, r, res - t[ls(o)].sum);
    	else return query(ls(o), l, mid, res);
    }
    
    void insert(int o, int l, int r, int x, int val) {
    	if(l == r) { t[o].num ++; t[o].sum += val; return ; }
    	if(x <= mid) insert(ls(o), l, mid, x, val);
    	if(x > mid) insert(rs(o), mid + 1, r, x, val);
    	t[o].num = t[ls(o)].num + t[rs(o)].num;
    	t[o].sum = t[ls(o)].sum + t[rs(o)].sum;
    }
    
    int main() {
    	
    	for(T = read(); T ; T --) {
    		n = read(); m = read();
    		build(1, 1, n);
    		for(int i = 1;i <= n; i++) a[i] = b[i] = read();
    		sort(b + 1, b + n + 1);
    		int cnt = unique(b + 1, b + n + 1) - b - 1;
    		for(int i = 1;i <= n; i++) {
    			int tmp = m - a[i], li = lower_bound(b + 1, b + n + 1, a[i]) - b;
    			if(tmp < 0) { printf("%d ", i); }
    			else {
    				int num = query(1, 1, n, tmp);
    				printf("%d ", i - num - 1);
    				insert(1, 1, n, li, a[i]);
    			}
    		}
    		printf("
    ");
    	}
    	
    	return 0;
    }
    

    T3

    ​ 题目大意:

    ​ 给定(n)个数(有正有负),可以任取前几个把前几个数分成(k)段,使最大的那一段的总和最小,输出这个最小值.(n <= 1e5).

    ​ 二分 + DP + 离散化 + 树状数组

    ​ 二分的话当然是二分那个最大值, 设为(mid),然后跑一边DP,(f[i])表示前(i)个数能分成的小于等于(mid)的段数最多有几个,那么DP转移方程就是:

    (f[i] = max(f[j] + 1) (sum[i] - sum[j] <= mid)).(sum)表示前缀和.

    ​ 但是有一点要注意:当(max(f[j]) = 0)时,要判断(sum[i])是否小于等于(mid),如果不是,那么(f[i])还等于0.

    ​ 我们发现这个式子是(O(N ^ 2))的,考虑用树状数组优化一下,怎么优化呢?

    ​ 我们要找的(f[j])一定是满足这个条件的(sum[j] >= sum[i] - mid),我们开一个权值树状数组,(t[x])维护比(x)大的最大的(f)值, 离散化之后查询和插入就好了.

    ​ 总复杂度(O(n log^2n)).

    #include <bits/stdc++.h>
    
    #define mid ((l + r) >> 1)
    
    using namespace std;
    
    inline long long read() {
    	long long s = 0, f = 1; char ch;
    	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    	return s * f;
    }
    
    const int N = 1e5 + 5;
    const long long inf = 1e18;
    int n, k, cnt;
    long long ans;
    int a[N], f[N], t[N];
    long long b[N], sum[N];
    
    int lowbit(int x) { return x & (-x); }
    
    void change(int x, int val) { for(; x ; x -= lowbit(x)) t[x] = max(t[x], val); }
    
    int query(int x) { int res = 0; for(; x < N; x += lowbit(x)) res = max(res, t[x]); return res; }
    
    int judge(long long Mid) {
    	for(int i = 1;i < N; i++) t[i] = 0;
    	for(int i = 1;i <= n; i++) {
    		int li = lower_bound(b + 1, b + cnt + 1, sum[i] - Mid) - b;
    		int ll = lower_bound(b + 1, b + cnt + 1, sum[i]) - b;
    		int tmp = query(li) + 1;
    		if(tmp == 1 && sum[i] > Mid) f[i] = 0;
    		else f[i] = tmp; 
    		change(ll, f[i]);
    		if(f[i] >= k) return 1;
    	}
    	return 0;
    }
    
    int main() {
    	
    	for(int T = read(); T ; T --) {
    		n = read(); k = read();
    		for(int i = 1;i <= n; i++) a[i] = read(), b[i] = sum[i] = sum[i - 1] + a[i];
    		sort(b + 1, b + n + 1);
    		cnt = unique(b + 1, b + n + 1) - b - 1;
    		long long l = -1e10, r = 1e10;
    		while(l <= r) {
    			if(judge(mid)) ans = mid, r = mid - 1;
    			else l = mid + 1;
    		}
    		printf("%lld
    ", ans);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    、你对测试最大的兴趣在哪里?为什么?
    软件配置管理的作用?软件配置包括什么?
    什么是软件测试?软件测试的目的与原则
    生命周期阶段:
    白盒测试的优点有:
    黑盒测试的缺点有:
    什么是软件质量?
    软件配置管理的作用?软件配置包括什么?
    什么是测试用例 什么是测试脚本 两者的关系是什么?
    软件的安全性应从哪几个方面去测试?
  • 原文地址:https://www.cnblogs.com/czhui666/p/13894568.html
Copyright © 2011-2022 走看看