zoukankan      html  css  js  c++  java
  • Codeforces Edu Round 66 A-E

    A. From Hero to Zero

    通过取余快速运行第一步即可。由于(a \% b (a >= b) <= frac{a}{2})。所以总复杂度不超过(O(log_2n))

    #include <cstdio>
    #include <iostream>
    using namespace std;
    typedef long long LL;
    int main(){
    	int T; scanf("%d", &T);
    	while(T--){
    		LL n, k, ans = 0;
    		scanf("%lld%lld", &n, &k);
    		while(n){
    			if(n % k) ans += n % k, n -= n % k;
    			if(n)n /= k, ans++; 
    		}
    		printf("%lld
    ", ans);
    	}
    	return 0;
    }
    

    B. Catch Overflow!

    循环本质其实是栈的思想,可以用(loop)表示这层要循环多少次。注意如果直接乘可能爆(long long)

    其实当(loop > 2 ^ {32} - 1),后面的只要有(add)都不行了,所以只要用个(flag)记录就行了...

    #include <cstdio>
    #include <iostream>
    #include <string>
    #include <stack> 
    using namespace std;
    typedef long long LL;
    const LL INF = (1ll << 32) - 1; 
    LL n = 0, loop = 1;
    stack<int> s;
    string ch;
    int x, flag = 0;
    int main(){
    	ios::sync_with_stdio(false);
    	int T; cin >> T;
    	while(T--){
    		cin >> ch;
    		if(ch == "add"){ 
    			if(loop > INF){
    				cout << "OVERFLOW!!!" << endl;
    				return 0;
    			}
    			n += loop;
    		}else if(ch == "for"){
    			cin >> x;
    			if(loop > INF) {
    				flag++;
    				continue;
    			}
    			s.push(x);
    			loop *= x;
    		}else if(ch == "end"){
    			if(flag) {
    				flag --;
    				continue;
    			}
    			loop /= s.top();
    			s.pop(); 
    		}
    		if(n > INF){
    			cout << "OVERFLOW!!!" << endl;
    			return 0;
    		}
    	}
    	cout << n << endl;
    	return 0;
    }
    
    

    C. Electrification

    注意数据是单调递增的,所以容易想到最短的一段必然是连续的,因为通过绝对值变成正的值顺序一定是(1, 2, 3....n),所以每次变成正的后,它可能是最小的,也有可能大于后面的一些,因为减的多了,所以整个区间会往后移动。我们可以尝试枚举每一个([i, i + k])的这个区间,发现能使最小的即变为((a[i + k] - a[i]) / 2),也就是全部都减((a[i + k] - a[i]) / 2)(可以向下取整)。可以用小根堆维护最小值。由于精度问题,第一个可以不用(/2)

    #include <cstdio>
    #include <iostream>
    #include <cmath> 
    #include <queue>
    #include <vector>
    using namespace std;
    typedef pair<int, int> PII;
    const int N = 200010;
    int n, k, a[N];
    priority_queue<PII, vector<PII>, greater<PII> > q;
    int main(){
    	int T; scanf("%d", &T);
    	while(T--){
    		while(q.size()) q.pop();
    		scanf("%d%d", &n, &k);
    		for(int i = 1; i <= n; i++)
    			scanf("%d", a + i);	
    		for(int i = 1; i + k <= n; i++)
    			q.push(make_pair(a[i + k] - a[i], (a[i] + a[i + k]) / 2));
    		printf("%d
    ", q.top().second);
    	}
    	return 0;
    }
    

    D. Array Splitting

    非常巧妙的做法,观察到让我们求的值其实是每一段的和$ * $ 相应的段数,但其实可以发现,一个(ans)的组成为:

    (1 * A + 2 * B + 3 * C = (A + B + C) + (B + C) + C)。实质上就是找到(k)个后缀和,将他们加起来求最大值。这样直接贪心求解即可,记得([1, n])这个区间必须选。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 300010;
    typedef long long LL;
    int n, k, a[N];
    LL ans, sum[N];
    int main(){
    	scanf("%d%d", &n, &k);
    	for(int i = 1; i <= n; i++) 
    		scanf("%d", a + i);
    	for(int i = n; i; i--)
    		sum[i] = sum[i + 1] + a[i];
    	sort(sum + 2, sum + 1 + n);
    	ans = sum[1];
    	for(int i = n; i >= n - k + 2; i--)	ans += sum[i];
    	printf("%lld
    ", ans);
    	return 0;
    }
    

    E. Minimal Segment Cover

    注意到(l)(r)的范围并不大,我们可以预处理出从(l)出发最远能到哪里(一条线段),注意(l)也可以是中间点。这样我们只需要逐个枚举即可。时间复杂度(SIZE ^ 2),可以用倍增的形式优化。具体方式很像(LCA),预处理每个(l)(2 ^ p(0 <= p <= lfloor log_2500000 floor))能到哪里即可。本质上就是枚举答案的二进制位即可。

    时间复杂度(O(slog_2s))(s)是数字范围)

    注意预处理顺序,要么(i)倒序枚举,要么(j)在第一个条件,否则没有正确的转移。

    #include <cstdio>
    #include <iostream>
    #include <cmath>
    using namespace std;
    const int N = 200010, SIZE = 500010, L = 19;
    int n, m, maxS = -1, f[SIZE][L];
    int main(){
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= n; i++){
    		int l, r; scanf("%d%d", &l, &r);
    		f[l][0] = max(f[l][0], r);
    		maxS = max(maxS, r);
    	}
    	for(int i = 1; i <= maxS; i++)
    		f[i][0] = max(f[i][0], f[i - 1][0]);
    	
    	for(int j = 1; j < L; j++)
    		for(int i = 0; i <= maxS; i++)
    			f[i][j] = f[f[i][j - 1]][j - 1];
    	
    	for(int i = 1; i <= m; i++){
    		int x, y, ans = 0;  scanf("%d%d", &x, &y);
    		for(int i = L - 1; ~i; i--)
    			if(f[x][i] < y) x = f[x][i], ans |= 1 << i;
    		if(f[x][0] >= y) printf("%d
    ", ans + 1);
    		else puts("-1");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    如何为你的Airtest报告自定义名称
    Go打包构建 生成32位64位应用程序 加入前端项目
    DNS解析与DNS缓存清理
    sharepoint2013安装记录
    C# winform自托管WebApi及身份信息加密、Basic验证、Http Message Handler、跨域配置
    IM扫码登录技术专题(四):你真的了解二维码吗?刨根问底、一文掌握!
    IM开发干货分享:万字长文,详解IM“消息“列表卡顿优化实践
    阿里IM技术分享(五):闲鱼亿级IM消息系统的及时性优化实践
    使用oracle序列+oracle定时任务获取每月从1开始的流水码
    为什么我的数据库查询越来越慢
  • 原文地址:https://www.cnblogs.com/dmoransky/p/11330238.html
Copyright © 2011-2022 走看看