2018 NOIP 普及组

文章目录

  • T1 标题统计
    • T1分析
  • T2 龙虎斗
    • T2分析
  • T3 摆渡车
    • T3分析
  • T4 对称二叉树
    • T4分析

T1 标题统计

题目点击→洛谷 P5015 标题统计

题目描述
凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符? 注意:标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字 符数时,空格和换行符不计算在内。

输入输出格式
输入格式:
输入文件只有一行,一个字符串 ss。

输出格式:
输出文件只有一行,包含一个整数,即作文标题的字符数(不含空格和换行符)。

输入输出样例
输入样例#1:
234
输出样例#1:
3
输入样例#2:
Ca 45
输出样例#2:
4
说明
【输入输出样例 1 说明】
标题中共有 3 3 3 个字符,这 3 3 3 个字符都是数字字符。

【输入输出样例 2 说明】
标题中共有 5 5 5 个字符,包括 1 1 1 个大写英文字母, 1 1 1 个小写英文字母和 2 2 2 个数字字符, 还有 1 1 1 个空格。由于空格不计入结果中,故标题的有效字符数为 4 4 4 个。

【数据规模与约定】
规定 ∣ s ∣ |s| s 表示字符串 s s s 的长度(即字符串中的字符和空格数)。
对于 40 % 40\% 40% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 ≤ |s| ≤ 5 1s5,保证输入为数字字符及行末换行符。
对于 80 % 80\% 80% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 ≤ |s| ≤ 5 1s5,输入只可能包含大、小写英文字母、数字字符及行末换行符。
对于 100 % 100\% 100% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 ≤ |s| ≤ 5 1s5,输入可能包含大、小写英文字母、数字字符、空格和行末换行符。

T1分析

送分题…

#include 

using namespace std;

int main()
{
    string s;
    int ans=0;
    while (cin >> s) 
        ans+=s.length();
    cout << ans << endl;
    return 0;
}

T2 龙虎斗

题目点击→洛谷 P5016 龙虎斗

题目描述
轩轩和凯凯正在玩一款叫《龙虎斗》的游戏,游戏的棋盘是一条线段,线段上有 n n n 个兵营(自左至右编号 1 ∼ n 1 \sim n 1n),相邻编号的兵营之间相隔 1 1 1 厘米,即棋盘为长度为 n − 1 n-1 n1 厘米的线段。 i i i 号兵营里有 c i c_i ci​ 位工兵。 下面图 1 1 1 n = 6 n=6 n=6 的示例:
2018 NOIP 普及组_第1张图片

轩轩在左侧,代表“龙”;凯凯在右侧,代表“虎”。 他们以 m m m 号兵营作为分界, 靠左的工兵属于龙势力,靠右的工兵属于虎势力,而第 m m m 号兵营中的工兵很纠结,他们不属于任何一方。

一个兵营的气势为:该兵营中的工兵数 × \times × 该兵营到 m m m 号兵营的距离;参与游戏 一方的势力定义为:属于这一方所有兵营的气势之和。
下面图 2 为 n = 6 , m = 4 n = 6,m = 4 n=6,m=4 的示例,其中红色为龙方,黄色为虎方:
2018 NOIP 普及组_第2张图片

游戏过程中,某一刻天降神兵,共有 s 1 s_1 s1 位工兵突然出现在了 p 1 p_1 p1​ 号兵营。作为轩轩和凯凯的朋友,你知道如果龙虎双方气势差距太悬殊,轩轩和凯凯就不愿意继续玩下去了。为了让游戏继续,你需要选择一个兵营 p 2 p_2 p2 ,并将你手里的 s 2 s_2 s2 位工兵全部派往 兵营 p 2 p_2 p2,使得双方气势差距尽可能小。

注意:你手中的工兵落在哪个兵营,就和该兵营中其他工兵有相同的势力归属(如果落在 m m m 号兵营,则不属于任何势力)。

输入输出格式
输入格式:
输入文件的第一行包含一个正整数 n n n,代表兵营的数量。

接下来的一行包含 n n n 个正整数,相邻两数之间以一个空格分隔,第 i i i 个正整数代 表编号为 i i i 的兵营中起始时的工兵数量 c i c_i ci

接下来的一行包含四个正整数,相邻两数间以一个空格分隔,分别代表 m , p 1 , s 1 , s 2 m,p_1,s_1,s_2 m,p1,s1,s2

输出格式:
输出文件有一行,包含一个正整数,即 p 2 p_2 p2 ,表示你选择的兵营编号。如果存在多个编号同时满足最优,取最小的编号。

输入输出样例
输入样例#1:
6
2 3 2 3 2 3
4 6 5 2
输出样例#1:
2
输入样例#2:
6
1 1 1 1 1 16
5 4 1 1
输出样例#2:
1
说明
【输入输出样例 1 说明】

见问题描述中的图 2。
双方以 m = 4 m=4 m=4 号兵营分界,有 s 1 = 5 s_1=5 s1=5 位工兵突然出现在 p 1 = 6 p_1=6 p1=6 号兵营。 龙方的气势为:
2 × ( 4 − 1 ) + 3 × ( 4 − 2 ) + 2 × ( 4 − 3 ) = 14 2 \times (4-1)+3 \times (4-2)+2 \times (4-3) = 14 2×(41)+3×(42)+2×(43)=14

虎方的气势为:
2 × ( 5 − 4 ) + ( 3 + 5 ) × ( 6 − 4 ) = 18 2 \times (5 - 4) + (3 + 5) \times (6 - 4) = 18 2×(54)+(3+5)×(64)=18
当你将手中的 s 2 = 2 s_2 = 2 s2=2 位工兵派往 p 2 = 2 p_2 = 2 p2=2 号兵营时,龙方的气势变为:
14 + 2 × ( 4 − 2 ) = 18 14 + 2 \times (4 - 2) = 18 14+2×(42)=18

此时双方气势相等。

【输入输出样例 2 说明】

双方以 m = 5 m = 5 m=5 号兵营分界,有 s 1 = 1 s_1 = 1 s1=1 位工兵突然出现在 p 1 = 4 p_1 = 4 p1=4 号兵营。
龙方的气势为:
1 × ( 5 − 1 ) + 1 × ( 5 − 2 ) + 1 × ( 5 − 3 ) + ( 1 + 1 ) × ( 5 − 4 ) = 11 1 \times (5 - 1) + 1 \times (5 - 2) + 1 \times (5 - 3) + (1 + 1) \times (5 - 4) = 11 1×(51)+1×(52)+1×(53)+(1+1)×(54)=11

虎方的气势为:
16 × ( 6 − 5 ) = 16 16 \times (6 - 5) = 16 16×(65)=16

当你将手中的 s 2 = 1 s_2 = 1 s2=1 位工兵派往 p 2 = 1 p_2 = 1 p2=1 号兵营时,龙方的气势变为:
11 + 1 × ( 5 − 1 ) = 15 11 + 1 \times (5 - 1) = 15 11+1×(51)=15

此时可以使双方气势的差距最小。

【数据规模与约定】
1 < m < n , 1 ≤ p 1 ≤ n 1 < m < n,1 ≤ p_1 ≤ n 1<m<n,1p1n
对于 20 % 20\% 20% 的数据, n = 3 , m = 2 , c i = 1 , s 1 , s 2 ≤ 100 n = 3,m = 2, c_i = 1, s_1,s_2 ≤ 100 n=3,m=2,ci=1,s1,s2100
另有 20 % 20\% 20% 的数据, n ≤ 10 , p 1 = m , c i = 1 , s 1 , s 2 ≤ 100 n ≤ 10, p_1 = m, c_i = 1, s_1,s_2 ≤ 100 n10,p1=m,ci=1,s1,s2100
对于 60 % 60\% 60% 的数据, n ≤ 100 , c i = 1 , s 1 , s 2 ≤ 100 n ≤ 100, c_i = 1, s_1,s_2 ≤ 100 n100,ci=1,s1,s2100
对于 80 % 80\% 80% 的数据, n ≤ 100 , c i , s 1 , s 2 ≤ 100 n ≤ 100, c_i,s_1,s_2 ≤ 100 n100,ci,s1,s2100
对于 100 % 100\% 100% 的数据, n ≤ 1 0 5 n≤10^5 n105, c i , s 1 , s 2 ≤ 1 0 9 c_i,s_1,s_2≤10^9 ci,s1,s2109

T2分析

先算出左边和右边的和,然后暴力模拟当前 s 2 s_2 s2 放在 [ 1 , n ] [1,n] [1,n] 中任意一个位置的情况,求出一个最小差值 a b s ( l e f t − r i g h t ) abs(left-right) abs(leftright)即可
注意细节, n ≤ 1 0 5 n≤10^5 n105, c i , s 1 , s 2 ≤ 1 0 9 c_i,s_1,s_2≤10^9 ci,s1,s2109,求和的结果会达到 1 0 14 10^{14} 1014,所以要long long,以及 p 1 p_1 p1可能在左边也可能在右边,也可能在 m m m 上,还有就是手里这 s 2 s_2 s2 个人同样是可以放在 m m m 中的

#include 
#include 
#include 
#include 
#include  
using namespace std;

long long a[100100];

int main()
{
	int n;scanf("%d",&n);
	for (int i = 1 ; i <= n ; ++i)
		scanf("%lld",&a[i]);
	long long m,p1,s1,s2;
	scanf("%lld%lld%lld%lld",&m,&p1,&s1,&s2);
	long long left = 0,right = 0;
	for (int i = 1 ; i < m  ; ++i){
		left += a[i] * (m - i);
	}
	for (int i = m + 1 ; i <= n ; ++i){
		right += a[i] * (i - m);
	}
	if (p1 < m) left += (m - p1) * s1;
	if (p1 > m) right += (p1 - m) * s1;
	long long sum = abs(right - left),ans = m;
	for (int i = 1 ; i <= n ; ++i){
		long long vl = left;
		long long vr = right;
		if (i < m) vl += (m - i) * s2;
		if (i > m) vr += (i - m) * s2;
		long long vsum = abs(vl - vr);
		if (vsum < sum){
			ans = i;
			sum = vsum;
		}
	}
	printf("%lld\n",ans);
	return 0;
} 

T3 摆渡车

题目点击→ 洛谷 P5017 摆渡车

题目描述
n n n 名同学要乘坐摆渡车从人大附中前往人民大学,第 i i i 位同学在第 t i t_i ti 分钟去 等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、 把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费 m m m 分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。

凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?

注意:摆渡车回到人大附中后可以即刻出发。

输入输出格式
输入格式:
第一行包含两个正整数 n , m n,m n,m,以一个空格分开,分别代表等车人数和摆渡车往返 一趟的时间。
第二行包含 n n n 个正整数,相邻两数之间以一个空格分隔,第 i i i 个非负整数 t i t_i ti 代 表第 i i i 个同学到达车站的时刻。

输出格式:
输出一行,一个整数,表示所有同学等车时间之和的最小值(单位:分钟)。

输入输出样例
输入样例#1:
5 1
3 4 4 3 5
输出样例#1:
0
输入样例#2:
5 5
11 13 1 5 5
输出样例#2:
4
说明
【输入输出样例 1 说明】

同学 1 1 1 和同学 4 4 4 在第 3 3 3 分钟开始等车,等待 0 0 0 分钟,在第 3 3 3 分钟乘坐摆渡车出发。摆渡车在第 4 4 4 分钟回到人大附中。
同学 2 2 2 和同学 3 3 3 在第 4 4 4 分钟开始等车,等待 0 0 0 分钟,在第 4 4 4 分钟乘坐摆渡车 出发。摆渡车在第 5 5 5 分钟回到人大附中。
同学 5 5 5 在第 5 5 5 分钟开始等车,等待 0 0 0 分钟,在第 5 5 5 分钟乘坐摆渡车出发。自此 所有同学都被送到人民大学。总等待时间为 0 0 0

【输入输出样例 2 说明】

同学 3 3 3 在第 1 1 1 分钟开始等车,等待 0 0 0 分钟,在第 1 1 1 分钟乘坐摆渡车出发。摆渡 车在第 6 6 6 分钟回到人大附中。
同学 4 4 4 和同学 5 5 5 在第 5 5 5 分钟开始等车,等待 1 1 1 分钟,在第 6 6 6 分钟乘坐摆渡车 出发。摆渡车在第 11 11 11 分钟回到人大附中。
同学 1 1 1 在第 11 11 11 分钟开始等车,等待 2 2 2 分钟;同学 2 2 2 在第 13 13 13 分钟开始等车, 等待 0 0 0 分钟。他/她们在第 13 13 13 分钟乘坐摆渡车出发。自此所有同学都被送到人民大学。 总等待时间为 4 4 4
可以证明,没有总等待时间小于 4 4 4 的方案。

【数据规模与约定】
对于 10 % 10\% 10% 的数据, n ≤ 10 , m = 1 , 0 ≤ t i ≤ 100 n ≤ 10, m = 1, 0 ≤ t_i ≤ 100 n10,m=1,0ti100
对于 30 % 30\% 30% 的数据, n ≤ 20 , m ≤ 2 , 0 ≤ t i ≤ 100 n ≤ 20, m ≤ 2, 0 ≤ t_i ≤ 100 n20,m2,0ti100
对于 50 % 50\% 50% 的数据, n ≤ 500 , m ≤ 100 , 0 ≤ t i ≤ 1 0 4 n ≤ 500, m ≤ 100, 0 ≤ t_i ≤ 10^4 n500,m100,0ti104
另有 20 % 20\% 20% 的数据, n ≤ 500 , m ≤ 10 , 0 ≤ t i ≤ 4 × 1 0 6 n ≤ 500, m ≤ 10, 0 ≤ t_i ≤ 4 \times 10^6 n500,m10,0ti4×106
对于 100 % 100\% 100% 的数据, n ≤ 500 , m ≤ 100 , 0 ≤ t i ≤ 4 × 1 0 6 n ≤ 500, m ≤ 100, 0 ≤ t_i ≤ 4 \times 10^6 n500,m100,0ti4×106

T3分析

dp或者记忆化搜索。
相对来说dp对算法要求高一些,需要考虑状态转移的优化或者剪枝
记忆化搜索相对来说简单一些,比赛的时候,既然可以想的到记忆化搜索,何必再去推个dp公式呢…当然10分钟解决dp所有问题的dalao就不用考虑这种东西了…
首先考虑一下这个问题中存在的状态,显然是 [ 人 ] [ 时 间 ] [人][时间] [][]两者的结合,那么考虑 f [ i ] [ j ] f[i][j] f[i][j],第 i i i 个人,考虑时间 j j j ,能达到的最佳方案,但是显然 j j j 会达到 4 × 1 0 6 4 \times 10^6 4×106,但是这里我们可以发现一件事,一个人是不可能等待超过 m m m 分钟,所以其实状态可以表示成
f [ i ] [ j ] 表 示 到 第 i 个 人 , 他 的 等 待 时 间 是 j 的 时 候 能 达 到 的 最 佳 方 案 f[i][j]表示到第 i 个人,他的等待时间是 j 的时候能达到的最佳方案 f[i][j]ij
那么思考一下状态转移…显然最容易想到的状态就是对当前状态 f [ i ] [ j ] f[i][j] f[i][j] 考虑这辆车直接发车,或者等第 i + 1 i + 1 i+1个同学来,或者继续等到 i + 2 i + 2 i+2 个同学来。
然后考虑一下复杂度,显然 O ( n 2 ∗ m ) O(n^2*m) O(n2m)足矣…那就,做完了呀

#include 
#include 
#include 
#include 
#include 
#include  
using namespace std;
int n,m;
int a[10000];
int f[550][550]; //第i个人等待时间为j的最佳结果 
int solve(int now,int Time){
	//n个人都结束了则返回0 
	if (now >= n ) return 0;
	//若当前时间<当前同学的来的时间,则将时间拉到当前同学来的时间 
	if (a[now] > Time) return solve(now,a[now]);
	//当前状态出现过 
	if (f[now][Time - a[now]]) return f[now][Time - a[now]];
	int sum = 0,ans = 0;
	int i = now;
	for (; i < n ;++i){
		if (a[i] > Time) break;
		sum += a[i];
		ans += Time - a[i];
	}
	ans += solve(i , Time + m);
	for (; i < n ; ++i){
		sum += a[i];
		ans = min(ans, solve(i + 1,a[i] + m) + a[i] * (i - now + 1) - sum);
	}
	return f[now][Time - a[now]] = ans; 
}


int main(){
	scanf("%d%d",&n,&m);
	for (int i = 0 ; i < n ; ++i) scanf("%d",&a[i]);
	sort(a,a+n);
	printf("%d\n",solve(0,0));
	return 0;
} 

T4 对称二叉树

点击查看→ 洛谷 P5018 对称二叉树

题目描述
一棵有点权的有根树如果满足以下条件,则被轩轩称为对称二叉树:

二叉树;
将这棵树所有节点的左右子树交换,新树和原树对应位置的结构相同且点权相等。
下图中节点内的数字为权值,节点外的 idid 表示节点编号。
2018 NOIP 普及组_第3张图片

现在给出一棵二叉树,希望你找出它的一棵子树,该子树为对称二叉树,且节点数 最多。请输出这棵子树的节点数。

注意:只有树根的树也是对称二叉树。本题中约定,以节点 T T T 为子树根的一棵“子 树”指的是:节点 T T T 和它的全部后代节点构成的二叉树。

输入输出格式
输入格式:
第一行一个正整数 n n n,表示给定的树的节点的数目,规定节点编号 1 ∼ n 1 \sim n 1n,其中节点 1 1 1 是树根。

第二行 n n n 个正整数,用一个空格分隔,第 i i i 个正整数 v i v_i vi 代表节点 i i i 的权值。

接下来 n n n 行,每行两个正整数 l i , r i l_i, r_i li,ri ,分别表示节点 i i i 的左右孩子的编号。如果不存在左 / 右孩子,则以 − 1 -1 1 表示。两个数之间用一个空格隔开。

输出格式:
输出文件共一行,包含一个整数,表示给定的树的最大对称二叉子树的节点数。

输入输出样例
输入样例#1:
2
1 3
2 -1
-1 -1
输出样例#1:
1
输入样例#2:
10
2 2 5 5 5 5 4 4 2 3
9 10
-1 -1
-1 -1
-1 -1
-1 -1
-1 2
3 4
5 6
-1 -1
7 8
输出样例#2:
3

T4分析

第三题做太久了就没想到吧这第四题跟第三题比起来跟送的一样…
没啥东西…顶多也就是个PAT难度的题目…
首先考虑一点,直接check的复杂度是多少,乍一看以为是 O ( n 2 ) O(n^2) O(n2) 的就基本上崩了。。
实际上考虑最慢的情况就是一颗完全对称的树,那么遍历一次的复杂度是多少呢? O ( n ) O(n) O(n)因为每个点都要被访问到,然而并不是这样…显然每次左右分别往下遍历的话,遍历一次的复杂度也就只有 O ( l o g n ) O(logn) O(logn)罢了…所以…就做完了呀… O ( n l o g n ) O(nlogn) O(nlogn)就过了…甚至还可以做一下优化,比如先预处理出当前节点下子树的大小,那么每次在check之前可以判断…加个最优化剪枝虽然应该没什么大用

#include 
#include 
#include 
#include 
#include 
#include  
using namespace std;
int n;
int a[1001000],lson[1001000],rson[1001000];

int check(int l,int r){
	if (l == -1 && r == -1) return 1;
	if (l == -1 || r == -1) return -1;
	if (a[l] != a[r]) return -1;
	int lval = check(lson[l],rson[r]);
	int rval = check(rson[l],lson[r]);
	if (lval == -1 || rval == -1) return -1;
	return lval + rval + 1;
}

int main() {
	scanf("%d",&n);
	for (int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]);
	for (int i = 1 ; i <= n ; ++i){
		scanf("%d%d",&lson[i],&rson[i]);
	}
	int ans = 1;
	for (int i = 1 ; i <= n ; ++i){
		int temp = check(lson[i],rson[i]);
		if (temp != -1) ans = max(ans,temp);
	}
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(acm,基础内容,noip)