Advertisement

上海市计算机学会竞赛平台 2月月赛 丙组

阅读量:

T1 格式改写

题目描述

给定一个仅由拉丁字符组成字符序列,需要改写一些字符的大小写,使得序列全部变成大写或全部变成小写,请统计最少修改多少个字符才能完成这项任务。

输入格式

一个字符序列:保证仅由拉丁字符构成

输出格式

单个整数:表示最少修改次数

数据范围

设输入的字符数量为 n,则保证 1≤n≤100,000

样例数据

输入:

TheQuickBrownFoxJumpsOverTheLazyDog

输出:

9

说明:

将大写改小写

分析

题意

将整个字符串改为大写或小写,输出最小修改次数

思路

将整个字符串查一遍,记录其中大写和小写字母的个数,输出最小值

代码
复制代码
    #include <bits/stdc++.h>
    using namespace std;
    
    string s;
    
    int main(){
    	getline(cin, s);
    	int len = s.size();
    	int t = 0, l = 0;
    	for (int i = 0; i < len; i++){
    		if (islower(s[i]))
    			l++;
    		else
    			t++;
    	}
    	cout << min(t, l) << endl;
    	return 0;
    }

T2 倍数统计

题目描述

给定整数 a, b 与正整数 c,求出在 a 到 b 之间(包含 a 与 b)有多少整数是 cc 的倍数。

输入格式

第一行:两个整数 a 与 b;
第二行:单个正整数 c。

输出格式

单个整数:表示答案。

数据范围

-109≤a≤b≤109

1≤c≤109

样例数据

输入:

4 6
5

输出:

1

分析

题意

输出a~b中c的倍数

思路1

从a循环到b,记录c倍数的个数,但数据量太大,会超时。

思路2

假设a~b中有个数n是c的倍数,那么n+c一定也是c的倍数。
那么我们可以先循环找到从a开始第一个c的倍数n,再求出n~b中有几个c。

代码
复制代码
    #include <bits/stdc++.h>
    using namespace std;
    
    long long a, b, c;
    
    int main(){
       cin >> a >> b >> c;
       int num, ans = 1;
       for (int i = a; i <= b; i++)
       	if (i % c == 0){
       		num = i;
       		break;
       	}
       ans += (b - num) / c;
       cout << ans << endl;
       return 0;
    }

T3 区间的并

题目描述

给定一个数轴上的 n 个闭区间,第 i 个闭区间的两端点为[a_i,b_i],它们的并集可以表示为若干不相交的闭区间,请按照左端点从小到大的顺序输出这些区间的并集。

输入格式

第一行:单个整数 n;
第二行到第 n+1 行:每行两个整数 a_ib_i 表示一个闭区间 [a_i,b_i]

输出格式

若干行:表示输入区间的并集。每行两个整数,表示一个闭区间的两个端点,这些闭区间应该按照起点从小到大排序。

数据范围

对于 50% 的数据,1≤n≤104, 0 \leq a_i\leq b_i \leq 104
对于 100% 的数据,1≤n≤105 ,0≤a_ib_i≤109

样例数据

输入:

3
10 12
1 3
2 5

输出:

1 5
10 12

分析

题意

告诉你n区间的两个端点,如果有重复的就并成一个
注意:如区间[1,2]和区间[3,4]是两个区间

思路1:模拟

建立一个数组,将区间填上数字,填完从头扫一遍,只要不空格就输出。
而相邻区间的问题可以将区间的首位乘2,这样相邻的区间内会空一个,输出时除2即可。
但时间复杂度太高,只能拿50分。

思路2

先将数据存入结构体中,然后按左端点排序。这是,如果一个区间的左端点在上一个区间的右端点右面,那这一定是两个不同的区间,反之则并为一个区间。
代码:

复制代码
    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 1e5 + 10;
    
    struct nod{
    	int a, b;
    };
    
    bool cmp(nod a, nod b){
    	return a.a < b.a;
    }
    
    nod x[MAXN];
    int n;
    int be, en;
    
    int main(){
    	cin >> n;
    	for (int i = 1; i <= n; i++){
    		cin >> x[i].a >> x[i].b;
    	}
    	sort(x + 1, x + n + 1, cmp);
    	int be = x[1].a, en = x[1].b;
    	for (int i = 2; i <= n; i++){
    		if (x[i].a > en){
    			cout << be << " " << en << endl;
    			be = x[i].a;
    			en = x[i].b;
    		}
    		if (x[i].b > en){
    			en = x[i].b;
    		}
    	}
    	cout << be << " " << en << endl;
    	return 0;
    }

T4 平分数字(一)

题目描述

给定 n 个整数:a_1,a_2,\cdots,a_n,请判定能否将它们分成两个部分(不得丢弃任何数字),每部分的数字之和一样大。

输入格式

第一行:单个整数 n;
第二行:n 个整数,表示 a_1,a_2,\cdots,a_n

输出格式

若能否平分,输出 Matched,否则输出 No

数据范围

对于 50% 的数据,1≤n≤18;
对于 100% 的数据,1≤n≤24;
−10,000,000≤a_i≤10,000,000

样例数据

输入:

4
1 2 3 4

输出:

Matched

说明:

1 + 4 = 2 + 3

输入:

3
2 2 2

输出:

No

分析

题意

给定n个数,判断是否能分为两组和相同的数字。

思路:搜索

这题的n只到24,所以即使把所有可能讨论一遍也只有224(16,777,216<100,000,000)种情况。当然,题目只要求判断是否有解,所以我们找出一种后就可以立即暂停。并且,如果n个数的和是奇数,那么不可能有解。
代码:

复制代码
    #include <bits/stdc++.h>
    using namespace std;
    
    int n, sum, a[30];
    bool flag = false;
    
    void dfs(int s, int i){
    	if (flag == true){
    		return ;
    	}
    	if (s == sum){
    		flag = true;
    		return ;
    	}
    	if (i == n)
    		return ;
    	dfs(s + a[i + 1], i + 1);
    	dfs(s, i + 1);
    	return ;
    }
    
    int main(){
    	cin >> n;
    	for (int i = 1; i <= n; i++){
    		cin >> a[i];
    		sum += a[i];
    	}
    	if (sum % 2 == 0){
    		sum /= 2;
    		dfs(0, 0);
    	}
    	if (flag)
    		cout << "Matched" << endl;
    	else
    		cout << "No" << endl;
    	return 0;
    }

T5 圆环三染色

题目描述

有一个圆环上有 n 个点,一个染色方案需要为每个点分配三种颜色中的一种,且圆环上相邻的点颜色不能相同。

请求出有多少种染色方案。答案可能很大,输出模 1,000,000,007 的余数。

输入格式

单个整数表示 n。

输出格式

表示方案数模 1,000,000,007 的余数。

数据范围

对于 30% 的数据,1≤n≤20;
对于 60% 的数据,1≤n≤1,000,000;
对于 100% 的数据,1≤n≤1018

样例数据

输入:

1

输出:

3

输入:

3

输出:

6

分析

题意

给定一个有n个格子的圆环和三种染料,问有几种涂法。

思路1:搜索(30分)

建立一个数组,在每个位置填数,保证不与前一个相同,如果是第n个,则多判断是否与第一个相同,否则记录。
代码:

复制代码
    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 1e6 + 10;
    
    int n, ans = 0;
    int a[MAXN];
    
    void dfs(int i){
    	if (i == n + 1){
    		if (a[n] != a[1]){
    			ans++;
    		}
    		return;
    	}
    	for (int j = 1; j <= 3; j++){
    		if (i == 1 || j != a[i - 1]){
    			a[i] = j;
    			dfs(i + 1);
    		}			
    	}
    	return;
    }
    
    int main(){
    	cin >> n;
    	if (n == 1)
    		cout << 3 << endl;
    	else{
    		dfs(1);
    		cout << ans << endl;
    	}	
    	return 0;
    }

思路2:递归(60分)

我们看一个表格

n f(n)
1 3
2 6
3 6
4 18
5 30
6 66
7 126
8 258

可以看出,当n大于3时
当n为奇数时:f(n)=2f(n-1)+6
当n为偶数时:f(n)=2f(n-1)-6
所以得出代码:

复制代码
    #include <bits/stdc++.h>
    using namespace std;
    const int mod = 1e9 + 7;
    
    long long n, ans = 0;
    
    int f(long long i){
    	if (i == 1) return 3;
    	if (i == 2 || i == 3) return 6;
    	if (i % 2 == 0){
    		return (f(i - 1) % mod * 2 % mod + 6) % mod;
    	}else{
    		return (f(i - 1) % mod * 2 % mod - 6) % mod;
    	}
    }
    
    int main(){
    	cin >> n;
    	cout << f(n) << endl;
    	return 0;
    }

思路3:快速幂(100分)

还是这个表格:

n f(n)
1 3
2 6
3 6
4 18
5 30
6 66
7 126
8 258

我们发现,当n>3时:
当n为奇数时:f(n)=2^n-2
当n为偶数时:f(n)=2^n+2
所以只要明如何求出2n即可。这是我们可以用快速幂(参考染色问题
代码如下:

复制代码
    #include <bits/stdc++.h>
    using namespace std;
    const int mod = 1e9 + 7;
    
    long long n;
    
    long long f(long long a){
    	if (a == 0) return 1;
    	long long x = f(a / 2);
    	if (a % 2)
    		return x * x % mod * 2 % mod;
    	return x * x % mod;
    }
    
    int main(){
    	cin >> n;
    	int ans = f(n);
    	if (n == 1) 
    		cout << 3 << endl;
    	else if (n % 2 == 0)
    		cout << (ans + 2) % mod << endl;
    	else
    		cout << (ans - 2 + mod) % mod << endl;
    	return 0;
    }

全部评论 (0)

还没有任何评论哟~