1040 description
字符串 APPAPT 中包含了两个单词 PAT,其中第一个 PAT 是第 2 位§,第 4 位(A),第 6 位(T);第二个 PAT 是第 3 位§,第 4 位(A),第 6 位(T)。
现给定字符串,问一共可以形成多少个 PAT?
输入格式:
输入只有一行,包含一个字符串,长度不超过10
5
,只包含 P、A、T 三种字母。
输出格式:
在一行中输出给定字符串中包含多少个 PAT。由于结果可能比较大,只输出对 1000000007 取余数的结果。
输入样例:
APPAPT
输出样例:
2
idea
pat的计数方式:对于一个a来说,
形成的pat的数量=该a前p的个数 * 该a后t的数量
先进行处理,从前往后计算每位当前左边及其本位共有的p个数
同理,从后往前计算每位当前右边及其本位共有的t个数
遇到a则计算以该a为中心位的pat个数,注意要及时取余,不然后两个测试点过不了
solution
#include<stdio.h>
#include<string.h>
int main(){
char s[100010];
int m = 0, n = 0, p[100010] = {0}, t = 0, count = 0;
gets(s);
for(int i = 0; i < strlen(s); i++){
if(i != 0) p[i] = p[i-1];//前面已有的p个数
if(s[i] == 'P') p[i]++;//当前位为P,加一
}
for(int i = strlen(s) - 1; i > 0; i--){
if(s[i] == 'T') t++;
else if(s[i] == 'A') count = (count + t*p[i]) % 1000000007;
}
printf("%d", count);
return 0;
}
1045description
著名的快速排序算法里有一个经典的划分过程:我们通常采用某种方法取一个元素作为主元,通过交换,把比主元小的元素放到它的左边,比主元大的元素放到它的右边。 给定划分后的 N 个互不相同的正整数的排列,请问有多少个元素可能是划分前选取的主元?
例如给定 N=5, 排列是1、3、2、4、5。则:
1 的左边没有元素,右边的元素都比它大,所以它可能是主元;
尽管 3 的左边元素都比它小,但其右边的 2 比它小,所以它不能是主元;
尽管 2 的右边元素都比它大,但其左边的 3 比它大,所以它不能是主元;
类似原因,4 和 5 都可能是主元。
因此,有 3 个元素可能是主元。
输入格式:
输入在第 1 行中给出一个正整数 N(≤10
5
); 第 2 行是空格分隔的 N 个不同的正整数,每个数不超过 10
9
。
输出格式:
在第 1 行中输出有可能是主元的元素个数;在第 2 行中按递增顺序输出这些元素,其间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
5
1 3 2 4 5
输出样例:
3
1 4 5
idea
前后都比的话有两三个测试点会超时
前面记录最大元素小优化的话,还是会有一个测试点不过
先排序,利用快速排序如果是主元的话,一定位置同有序序列。辅之前面无更大元素,能保证其后无更小元素。
一个测试点是0,而且需要多输出一个换行。
solution
#include<cstdio>
#include<algorithm>
using namespace std;
int main(){
int a[100010], b[100010], ans[100010] = {0}, n, p = 0, max;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", a + i);
b[i] = a[i];
}
sort(b, b + n);
max = a[0];
for(int i = 0; i < n; i++){
if(max > a[i]) continue;
else {
max = a[i];
if(a[i] == b[i])
ans[p++] = a[i];
}
}
printf("%d\n", p);
for(int i = 0; i < p; i++){
printf("%d", ans[i]);
if(i != p - 1) printf(" ");
}
printf("\n");
return 0;
}
小结
- 递推:递推算法是一种用若干步可重复运算来描述复杂问题的方法。递推是序列计算中的一种常用算法。通常是通过计算机前面的一些项来得出序列中的指定象的值。
static int fun2(int n){//斐波那契数列的递推实现
int a[] = new int[20] ;
a[1] = 1 ;
a[2] = 1 ;
for(int i=3 ; i<=n ;i++){
a[i] = a[i-1] + a[i-2] ;
}
return a[n] ;
}
有些题目可以尝试考虑是否存在递推关系。例如在序列题目中,假如序列的每一位锁需要计算的值都可以通过该位左右两侧的结果计算得到,就可以考虑所谓的“左右两侧的结果”是否能通过递推进行预处理来得到,以避免后续使用中的反复求解。
在数pat中,就是提前预处理,得到左边的结果,再依次处理右边的结果。
在快速排序中,利用左右两侧的互斥,确保前半部分都是小于当前位&当前位置与有序序列中的位置相同,则是主元。
还是有点迷糊晴神说的思路像的意思😔
子串简写
solution
注意首尾元素也可能相等,c语言网有相应的测试用例,不过蓝桥杯木得。
#include<iostream>
#include<string>
using namespace std;
const int maxn = 5e5 + 10;
int sum[maxn] = {0};
int main(){
int k;
long long ans = 0;
string s;
char l, r;
cin >> k >> s >> l >> r;
s = " " + s;
for(int i = 1; i < s.size(); i++){
sum[i] = sum[i - 1];//前缀和记录合法开头方案数
if(s[i] == l) sum[i]++;
if(s[i] == r && i >= k) ans += sum[i - (k - 1)];//递推,发现目标结尾,累计当前有的几种合法开头
}
cout << ans;
return 0;
}