题目点击→洛谷 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 1≤∣s∣≤5,保证输入为数字字符及行末换行符。
对于 80 % 80\% 80% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 ≤ |s| ≤ 5 1≤∣s∣≤5,输入只可能包含大、小写英文字母、数字字符及行末换行符。
对于 100 % 100\% 100% 的数据, 1 ≤ ∣ s ∣ ≤ 5 1 ≤ |s| ≤ 5 1≤∣s∣≤5,输入可能包含大、小写英文字母、数字字符、空格和行末换行符。
送分题…
#include
using namespace std;
int main()
{
string s;
int ans=0;
while (cin >> s)
ans+=s.length();
cout << ans << endl;
return 0;
}
题目点击→洛谷 P5016 龙虎斗
题目描述
轩轩和凯凯正在玩一款叫《龙虎斗》的游戏,游戏的棋盘是一条线段,线段上有 n n n 个兵营(自左至右编号 1 ∼ n 1 \sim n 1∼n),相邻编号的兵营之间相隔 1 1 1 厘米,即棋盘为长度为 n − 1 n-1 n−1 厘米的线段。 i i i 号兵营里有 c i c_i ci 位工兵。 下面图 1 1 1 为 n = 6 n=6 n=6 的示例:
轩轩在左侧,代表“龙”;凯凯在右侧,代表“虎”。 他们以 m m m 号兵营作为分界, 靠左的工兵属于龙势力,靠右的工兵属于虎势力,而第 m m m 号兵营中的工兵很纠结,他们不属于任何一方。
一个兵营的气势为:该兵营中的工兵数 × \times × 该兵营到 m m m 号兵营的距离;参与游戏 一方的势力定义为:属于这一方所有兵营的气势之和。
下面图 2 为 n = 6 , m = 4 n = 6,m = 4 n=6,m=4 的示例,其中红色为龙方,黄色为虎方:
游戏过程中,某一刻天降神兵,共有 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×(4−1)+3×(4−2)+2×(4−3)=14
虎方的气势为:
2 × ( 5 − 4 ) + ( 3 + 5 ) × ( 6 − 4 ) = 18 2 \times (5 - 4) + (3 + 5) \times (6 - 4) = 18 2×(5−4)+(3+5)×(6−4)=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×(4−2)=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×(5−1)+1×(5−2)+1×(5−3)+(1+1)×(5−4)=11
虎方的气势为:
16 × ( 6 − 5 ) = 16 16 \times (6 - 5) = 16 16×(6−5)=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×(5−1)=15
此时可以使双方气势的差距最小。
【数据规模与约定】
1 < m < n , 1 ≤ p 1 ≤ n 1 < m < n,1 ≤ p_1 ≤ n 1<m<n,1≤p1≤n
对于 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,s2≤100
另有 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 n≤10,p1=m,ci=1,s1,s2≤100
对于 60 % 60\% 60% 的数据, n ≤ 100 , c i = 1 , s 1 , s 2 ≤ 100 n ≤ 100, c_i = 1, s_1,s_2 ≤ 100 n≤100,ci=1,s1,s2≤100
对于 80 % 80\% 80% 的数据, n ≤ 100 , c i , s 1 , s 2 ≤ 100 n ≤ 100, c_i,s_1,s_2 ≤ 100 n≤100,ci,s1,s2≤100
对于 100 % 100\% 100% 的数据, n ≤ 1 0 5 n≤10^5 n≤105, c i , s 1 , s 2 ≤ 1 0 9 c_i,s_1,s_2≤10^9 ci,s1,s2≤109
先算出左边和右边的和,然后暴力模拟当前 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(left−right)即可
注意细节, n ≤ 1 0 5 n≤10^5 n≤105, c i , s 1 , s 2 ≤ 1 0 9 c_i,s_1,s_2≤10^9 ci,s1,s2≤109,求和的结果会达到 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;
}
题目点击→ 洛谷 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 n≤10,m=1,0≤ti≤100
对于 30 % 30\% 30% 的数据, n ≤ 20 , m ≤ 2 , 0 ≤ t i ≤ 100 n ≤ 20, m ≤ 2, 0 ≤ t_i ≤ 100 n≤20,m≤2,0≤ti≤100
对于 50 % 50\% 50% 的数据, n ≤ 500 , m ≤ 100 , 0 ≤ t i ≤ 1 0 4 n ≤ 500, m ≤ 100, 0 ≤ t_i ≤ 10^4 n≤500,m≤100,0≤ti≤104
另有 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 n≤500,m≤10,0≤ti≤4×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 n≤500,m≤100,0≤ti≤4×106
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]表示到第i个人,他的等待时间是j的时候能达到的最佳方案
那么思考一下状态转移…显然最容易想到的状态就是对当前状态 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(n2∗m)足矣…那就,做完了呀
#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;
}
点击查看→ 洛谷 P5018 对称二叉树
题目描述
一棵有点权的有根树如果满足以下条件,则被轩轩称为对称二叉树:
二叉树;
将这棵树所有节点的左右子树交换,新树和原树对应位置的结构相同且点权相等。
下图中节点内的数字为权值,节点外的 idid 表示节点编号。
现在给出一棵二叉树,希望你找出它的一棵子树,该子树为对称二叉树,且节点数 最多。请输出这棵子树的节点数。
注意:只有树根的树也是对称二叉树。本题中约定,以节点 T T T 为子树根的一棵“子 树”指的是:节点 T T T 和它的全部后代节点构成的二叉树。
输入输出格式
输入格式:
第一行一个正整数 n n n,表示给定的树的节点的数目,规定节点编号 1 ∼ n 1 \sim n 1∼n,其中节点 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
第三题做太久了就没想到吧这第四题跟第三题比起来跟送的一样…
没啥东西…顶多也就是个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;
}