2020年大题

2020年省A一模

E、数位递增的数

一个正整数如果任何一个数位不大于右边相邻的数位,则称为一个数位递增的数,例如1135是一个数位递增的数,而1024不是一个数位递增的数。给定正整数 n,请问在整数 1 至 n 中有多少个数位递增的数?
【样例输入】
30
【样例输出】
26
【评测用例规模与约定】
对于 40% 的评测用例,1 <= n <= 1000。
对于 80% 的评测用例,1 <= n <= 100000。
对于所有评测用例,1 <= n <= 1000000。
思路:非递减数也就是从个位数非递增,常规遍历数字判断题。

bool judge(int x){//非递减数判断 
	int t=x%10;
	while (x){
		x/=10;
		if (t<x%10) return false;
		else t=x%10;
	}
	return true;
}
int main(){
	int n,cnt=0;
	cin>>n;
	for (int i=1;i<=n;i++){
		if (judge(i)) cnt+=1;
	}
	cout<<cnt;
	return 0;
}

F、三元组中心问题

在数列 a[1], a[2], …, a[n] 中,如果对于下标 i, j, k 满足 0<i<j<k<n+1 且 a[i]<a[j]<a[k],则称 a[i], a[j], a[k] 为一组递增三元组,a[j]为递增三元组的中心。
给定一个数列,请问数列中有多少个元素可能是递增三元组的中心。
【样例输入】
5
1 2 5 3 5
【样例输出】
2
【样例说明】
a[2] 和 a[4] 可能是三元组的中心。
【评测用例规模与约定】
对于 50% 的评测用例,2 <= n <= 100,0 <= 数列中的数 <= 1000。
对于所有评测用例,2 <= n <= 1000,0 <= 数列中的数 <= 10000。
思路:用node存储输入元素的值和初始位置,sort重排后对中间的数字进行两边判断。

struct node{int where,num;};
bool bmp(node a,node b){//递增排序 
	if (a.num==b.num) return a.where<b.where;
	return (a.num<b.num);
}
int main(){
	int n,in,cnt=0;
	cin>>n;
	node a[n+1];
	for (int i=0;i<n;i++){
		cin>>in;
		a[i+1]={i+1,in};
	}
	sort(a+1,a+n+1,bmp);
	for (int i=2;i<n;i++){//中间数 
		if (a[i].num>a[1].num&&a[i].num<a[n].num){
			int j,k;
			for (j=1;j<i&&a[j].num<a[i].num&&a[j].where>a[i].where;j++);
			if (j<i){//左侧有小的 
				for (k=n;k>i&&a[k].num>a[i].num&&a[k].where<a[i].where;k--);
				if (k>i) cnt+=1;//右侧有大的 
			}
		}
	}
	cout<<cnt;
	return 0;
}

G、音节判断

小明对类似于 hello 这种单词非常感兴趣,这种单词可以正好分为四段,第一段由一个或多个辅音字母组成,第二段由一个或多个元音字母组成,第三段由一个或多个辅音字母组成,第四段由一个或多个元音字母组成。给定一个单词,请判断这个单词是否也是这种单词,如果是请输出yes,否则请输出no。元音字母包括 a, e, i, o, u,共五个,其他均为辅音字母。
【样例输入】
lanqiao
【样例输出】
yes
【样例输入】
world
【样例输出】
no
【评测用例规模与约定】
对于所有评测用例,单词中的字母个数不超过100。
思路:对字符串进行遍历判断,记得第四段元音后不能有辅音!
易错点:welcome no

int main(){
	string in;
	int c=0,f1=0,f2=0,f3=0,f4=0;
	cin>>in;
	for (c;c<in.size();c++){
		if (in[c]!='a'&&in[c]!='e'&&in[c]!='i'&&in[c]!='o'&&in[c]!='u') f1=1;
		else break;
	}
	if (f1){//有辅音
		for (c;c<in.size();c++){
			if (in[c]=='a'||in[c]=='e'||in[c]=='i'||in[c]=='o'||in[c]=='u') f2=1;
			else break;
		}
		if (f2){//有元音
			for (c;c<in.size();c++){
				if (in[c]!='a'&&in[c]!='e'&&in[c]!='i'&&in[c]!='o'&&in[c]!='u') f3=1;
				else break;
			}
			if (f3){//有辅音 
				for (c;c<in.size();c++){
					if (in[c]=='a'||in[c]=='e'||in[c]=='i'||in[c]=='o'||in[c]=='u') f4=1;
					else break;
				}
				if (f4&&c==in.size()) cout<<"yes";//有元音且到结尾 
				else cout<<"no";
			}
			else cout<<"no";
		}
		else cout<<"no";	
	}
	else cout<<"no";
	return 0;
}

H、长草

小明有一块空地,他将这块空地划分为 n 行 m 列的小块,每行和每列的长度都为 1。小明选了其中的一些小块空地,种上了草,其他小块仍然保持是空地。
这些草长得很快,每个月,草都会向外长出一些,如果一个小块种了草,则它将向自己的上、下、左、右四小块空地扩展,这四小块空地都将变为有草的小块。请告诉小明,k 个月后空地上哪些地方有草。
【输入格式】
输入的第一行包含两个整数 n, m。
接下来 n 行,每行包含 m 个字母,表示初始的空地状态,字母之间没有空格。如果为小数点,表示为空地,如果字母为 g,表示种了草。
接下来包含一个整数 k。
【输出格式】
输出 n 行,每行包含 m 个字母,表示 k 个月后空地的状态。如果为小数点,表示为空地,如果字母为 g,表示长了草。
【样例输入】
4 5
.g…

…g…

2
【样例输出】
gggg.
gggg.
ggggg
.ggg.
【评测用例规模与约定】
对于 30% 的评测用例,2 <= n, m <= 20。
对于 70% 的评测用例,2 <= n, m <= 100。
对于所有评测用例,2 <= n, m <= 1000,1 <= k <= 1000。
用DFS写超时了TAT

#include <bits/stdc++.h>
#define maxn 1001
int n,m,k,X[4]={-1,1,0,0},Y[4]={0,0,-1,1};
char have[maxn][maxn],visit[maxn][maxn]; 
void grow(int x,int y,int cnt){
	if (x<1||x>n||y<1||y>m) return;
	if (cnt==k) return;
	for (int i=0;i<4;i++){
		have[x+X[i]][y+Y[i]]='g';
		grow(x+X[i],y+Y[i],cnt+1);
	}
}
int main(){
	cin>>n>>m;
	char ch;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			cin>>ch;
			have[i][j]=ch;
			if (ch=='g') visit[i][j]='1';
			else visit[i][j]='0';
		}
	}
	cin>>k;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			if (have[i][j]=='g'&&visit[i][j]=='1')//初始g处长草 
				grow(i,j,0);
		}
	}
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++) cout<<have[i][j];
		cout<<endl;
	}
	return 0;
}

改用BFS过掉了!

#include <bits/stdc++.h>
#define maxn 1000
using namespace std;
int n,m,k,X[4]={-1,1,0,0},Y[4]={0,0,-1,1};
char have[maxn][maxn],visit[maxn][maxn]; 
struct node{int x,y,cnt;};
queue<node> q; 
int main(){
	cin>>n>>m;
	char ch;
	for (int i=0;i<n;i++){
		for (int j=0;j<m;j++){
			cin>>ch;
			have[i][j]=ch;
			if (ch=='g'){
				q.push({i,j,1});//初始草位置 
				visit[i][j]='1';
			}
			else visit[i][j]='0';
		}
	}
	cin>>k;
	while (q.size()){
		node t=q.front();//队头 
		q.pop();
		if (t.cnt<=k){//可长草 
			for (int i=0;i<4;i++){
				if (visit[t.x+X[i]][t.y+Y[i]]=='0'&&t.x+X[i]>=0&&t.x+X[i]<n&&t.y+Y[i]>=0&&t.y+Y[i]<m){
					have[t.x+X[i]][t.y+Y[i]]='g';
					q.push({t.x+X[i],t.y+Y[i],t.cnt+1});
					visit[t.x+X[i]][t.y+Y[i]]='1';//标记走过 
				}
			}
		}
	}
	for (int i=0;i<n;i++){
		for (int j=0;j<m;j++) cout<<have[i][j];
		cout<<endl;
	}
	return 0;
}

I、序列计数

小明想知道,满足以下条件的正整数序列的数量:

  1. 第一项为 n;
  2. 第二项不超过 n;
  3. 从第三项开始,每一项小于前两项的差的绝对值。
    请计算,对于给定的 n,有多少种满足条件的序列。
    【输入格式】
    输入一行包含一个整数 n。
    【输出格式】
    输出一个整数,表示答案。答案可能很大,请输出答案除以10000的余数。
    【样例输入】
    4
    【样例输出】
    7
    【样例说明】
    以下是满足条件的序列:
    4 1
    4 1 1
    4 1 2
    4 2
    4 2 1
    4 3
    4 4
    【评测用例规模与约定】
    对于 20% 的评测用例,1 <= n <= 5;
    对于 50% 的评测用例,1 <= n <= 10;
    对于 80% 的评测用例,1 <= n <= 100;
    对于所有评测用例,1 <= n <= 1000。
    递归求和+用二维数组状态压缩
typedef long long ll;
ll n,mod=10000,mem[1001][1001];
ll dfs (int pre,int cur){
    if (cur<=0) return 0;//非正整数 
    if (mem[pre][cur]!=0) return mem[pre][cur];//已有值 
    return mem[pre][cur]=(1+dfs(pre,cur-1)+dfs(cur,abs(pre-cur)-1))%mod;//状态压缩 
}
int main() {
    cin>>n;
    cout<<dfs(n,n);
    return 0;
}

J、晚会节目单

小明要组织一台晚会,总共准备了 n 个节目。然后晚会的时间有限,他只能最终选择其中的 m 个节目。这 n 个节目是按照小明设想的顺序给定的,顺序不能改变。小明发现,观众对于晚会的喜欢程度与前几个节目的好看程度有非常大的关系,他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。小明给每个节目定义了一个好看值,请你帮助小明选择出 m 个节目,满足他的要求。
【输入格式】
输入的第一行包含两个整数 n, m ,表示节目的数量和要选择的数量。
第二行包含 n 个整数,依次为每个节目的好看值。
【输出格式】
输出一行包含 m 个整数,为选出的节目的好看值。
【样例输入】
5 3
3 1 2 5 4
【样例输出】
3 5 4
【样例说明】
选择了第1, 4, 5个节目。
【评测用例规模与约定】
对于 30% 的评测用例,1 <= n <= 20;
对于 60% 的评测用例,1 <= n <= 100;
对于所有评测用例,1 <= n <= 100000,0 <= 节目的好看值 <= 100000。
线段树?这得专门学一下子,看不懂TAT
两道20+题未填坑,解析先放在这里。

2020年省A二模

E、反倍数

给定三个整数 a, b, c,如果一个整数既不是 a 的整数倍也不是 b 的整数倍还不是 c 的整数倍,则这个数称为反倍数。请问在 1 至 n 中有多少个反倍数。
【样例输入】
30
2 3 6
【样例输出】
10
【样例说明】
以下这些数满足要求:1, 5, 7, 11, 13, 17, 19, 23, 25, 29。
【评测用例规模与约定】
对于 40% 的评测用例,1 <= n <= 10000。
对于 80% 的评测用例,1 <= n <= 100000。
对于所有评测用例,1 <= n <= 1000000,1 <= a <= n,1 <= b <= n,1 <= c <= n。
思路: 遍历比较慢,用n-倍数的个数

int main(){
	int n,a,b,c;
	map<int,int> m;
	cin>>n>>a>>b>>c;
	int t1=a,t2=b,t3=c;
	while (t1<=n||t2<=n||t3<=n){//去掉所有倍数 
		if (t1<=n){
			m[t1]=1;
			t1+=a;
		}
		if (t2<=n){
			m[t2]=1;
			t2+=b;
		}
		if (t3<=n){
			m[t3]=1;
			t3+=c;
		}		
	}
	cout<<n-m.size();
	return 0;
}

F、凯撒加密

给定一个单词,请使用凯撒密码将这个单词加密。凯撒密码是一种替换加密的技术,单词中的所有字母都在字母表上向后偏移3位后被替换成密文。即a变为d,b变为e,…,w变为z,x变为a,y变为b,z变为c。例如,lanqiao会变成odqtldr。
【样例输入】
lanqiao
【样例输出】
odqtldr
【评测用例规模与约定】
对于所有评测用例,单词中的字母个数不超过100。
思路:加数取模int char转换后输出即可

int main(){
	string in;
	cin>>in;
	for (int i=0;i<in.size();i++) cout<<char((in[i]-'a'+3)%26+'a');
	return 0;
}

G、螺旋填充

对于一个 n 行 m 列的表格,我们可以使用螺旋的方式给表格依次填上正整数,我们称填好的表格为一个螺旋矩阵。例如,一个 4 行 5 列的螺旋矩阵如下:
1 2 3 4 5
14 15 16 17 6
13 20 19 18 7
12 11 10 9 8
【输入格式】
输入的第一行包含两个整数 n, m,分别表示螺旋矩阵的行数和列数。
第二行包含两个整数 r, c,表示要求的行号和列号。
【输出格式】
输出一个整数,表示螺旋矩阵中第 r 行第 c 列的元素的值。
【样例输入】
4 5
2 2
【样例输出】
15
【评测用例规模与约定】
对于 30% 的评测用例,2 <= n, m <= 20。
对于 70% 的评测用例,2 <= n, m <= 100。
对于所有评测用例,2 <= n, m <= 1000,1 <= r <= n,1 <= c <= m
思路:遍历填充,哪没数字填哪

int main(){//矩阵初始化
	int n,m,x,y;
	cin>>n>>m>>x>>y;
    int cost[n+1][m+1];
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++) cost[i][j]=0;
    }
    //螺旋填充快速方法:扫描找没有经过的地方即可
    int num=1;
    for (int x=1;x<=(n+1)/2;x++){//重复多少次
        for (int i=1;i<=m;i++){//上
            if (cost[x][i]==0) cost[x][i]=num++;
        }
        for (int j=1;j<=n;j++){//右
            if (cost[j][m+1-x]==0) cost[j][m+1-x]=num++;
        }
        for (int i=m;i>0;i--){//下
            if (cost[n+1-x][i]==0) cost[n+1-x][i]=num++;
        }
        for (int j=n;j>0;j--){//左
            if (cost[j][x]==0) cost[j][x]=num++;
        }
    }
    cout<<cost[x][y];
    return 0;
}

H、摆动序列

如果一个序列的奇数项都比前一项大,偶数项都比前一项小,则称为一个摆动序列。即 a[2i]<a[2i-1], a[2i+1]>a[2i]。小明想知道,长度为 m,每个数都是 1 到 n 之间的正整数的摆动序列一共有多少个。
【输入格式】
输入一行包含两个整数 m,n。
【输出格式】
输出一个整数,表示答案。答案可能很大,请输出答案除以10000的余数。
【样例输入】
3 4
【样例输出】
14
【样例说明】
以下是符合要求的摆动序列:
2 1 2
2 1 3
2 1 4
3 1 2
3 1 3
3 1 4
3 2 3
3 2 4
4 1 2
4 1 3
4 1 4
4 2 3
4 2 4
4 3 4
【评测用例规模与约定】
对于 20% 的评测用例,1 <= n, m <= 5;
对于 50% 的评测用例,1 <= n, m <= 10;
对于 80% 的评测用例,1 <= n, m <= 100;
对于所有评测用例,1 <= n, m <= 1000。
递归全排列吧,能混多少分是多少分。

typedef long long ll;
ll m,n,res=0;
ll dfs (int cnt,int x){
    if (cnt==m){
    	res+=1;
		if (res>=10000) res-=10000; //取余 
    }
    else{
    	cnt+=1;
    	for (int i=1;i<=n;i++){//全排列 
    		if (cnt%2&&i>x) dfs(cnt,i);
    		else if (cnt%2==0&&i<x) dfs(cnt,i);
    		else continue;
    	}
    }
}
int main() {
	cin>>m>>n;
	for (int i=2;i<=n;i++) dfs(1,i);
	cout<<res;
    return 0;
}

I、通电

通电
【问题描述】
2015年,全中国实现了户户通电。作为一名电力建设者,小明正在帮助一带一路上的国家通电。这一次,小明要帮助 n 个村庄通电,其中 1 号村庄正好可以建立一个发电站,所发的电足够所有村庄使用。现在,这 n 个村庄之间都没有电线相连,小明主要要做的是架设电线连接这些村庄,使得所有村庄都直接或间接的与发电站相通。
在这里插入图片描述
在上式中 sqrt 表示取括号内的平方根。请注意括号的位置,高度的计算方式与横纵坐标的计算方式不同。由于经费有限,请帮助小明计算他至少要花费多少费用才能使这 n 个村庄都通电。
【输入格式】
输入的第一行包含一个整数 n ,表示村庄的数量。
接下来 n 行,每个三个整数 x, y, h,分别表示一个村庄的横、纵坐标和高度,其中第一个村庄可以建立发电站。
【输出格式】
输出一行,包含一个实数,四舍五入保留 2 位小数,表示答案。
【样例输入】
4
1 1 3
9 9 7
8 8 6
4 5 4
【样例输出】
17.41
【评测用例规模与约定】
对于 30% 的评测用例,1 <= n <= 10;
对于 60% 的评测用例,1 <= n <= 100;
对于所有评测用例,1 <= n <= 1000,0 <= x, y, h <= 10000。
最小生成树——并查集算法

J、植树

小明和朋友们一起去郊外植树,他们带了一些在自己实验室精心研究出的小树苗。小明和朋友们一共有 n 个人,他们经过精心挑选,在一块空地上每个人挑选了一个适合植树的位置,总共 n 个。他们准备把自己带的树苗都植下去。
然而,他们遇到了一个困难:有的树苗比较大,而有的位置挨太近,导致两棵树植下去后会撞在一起。他们将树看成一个圆,圆心在他们找的位置上。如果两棵树对应的圆相交,这两棵树就不适合同时植下(相切不受影响),称为两棵树冲突。小明和朋友们决定先合计合计,只将其中的一部分树植下去,保证没有互相冲突的树。他们同时希望这些树所能覆盖的面积和(圆面积和)最大。
【输入格式】
输入的第一行包含一个整数 n ,表示人数,即准备植树的位置数。
接下来 n 行,每行三个整数 x, y, r,表示一棵树在空地上的横、纵坐标和半径。
【输出格式】
输出一行包含一个整数,表示在不冲突下可以植树的面积和。由于每棵树的面积都是圆周率的整数倍,请输出答案除以圆周率后的值(应当是一个整数)。
【样例输入】
6
1 1 2
1 4 2
1 7 2
4 1 2
4 4 2
4 7 2
【样例输出】
12
【评测用例规模与约定】
对于 30% 的评测用例,1 <= n <= 10;
对于 60% 的评测用例,1 <= n <= 20;
对于所有评测用例,1 <= n <= 30,0 <= x, y <= 1000,1 <= r <= 1000。
20+题未填坑 先把大佬的解析放在这里。

2020年省A第一场

F、分类计数(15分)

输入一个字符串,请输出这个字符串包含多少个大写字母,多少个小写字母,多少个数字。
【样例输入】
1+a=Aab
【样例输出】
1
3
1
【评测用例规模与约定】
对于所有评测用例,字符串由可见字符组成,长度不超过 100。
啊这,string记得用getline小心空格,有手就行

int main(){
   	string in;
   	getline(cin,in);
   	int r1=0,r2=0,r3=0;
   	for (int i=0;i<in.size();i++){
   		if (in[i]>='A'&&in[i]<='Z') r1+=1;
   		else if (in[i]>='a'&&in[i]<='z') r2+=1;
   		else if (in[i]>='0'&&in[i]<='9') r3+=1;
   	}
   	cout<<r1<<"\n"<<r2<<"\n"<<r3;
    return 0;
}

G、

H、

I、

J、

未填坑题在这里

2020年省A第二场

F、成绩统计

小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整数。
【输入格式】
输入的第一行包含一个整数 n,表示考试人数。
接下来 n 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。
【输出格式】
输出两行,每行一个百分数,分别表示及格率和优秀率。百分号前的部分
四舍五入保留整数。
【样例输入】
7
80
92
56
74
88
100
0
【样例输出】
71%
43%
【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ n ≤ 100。
对于所有评测用例,1 ≤ n ≤ 10000。
按规则分情况讨论

int main(){
    int n,in;
    double cnt1=0,cnt2=0;
    cin>>n;
    for (int i=0;i<n;i++){
        cin>>in;
        if (in>59){
           cnt1+=1;
           if (in>84) cnt2+=1;
        }
    }
    cout<<int(100.0*cnt1/double(n)+0.5)<<"%\n"<<int(100.0*cnt2/double(n)+0.5)<<"%";
  return 0;
}

G、回文日期

2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,恰好是一个回文数。我们称这样的日期是回文日期。有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千年一遇”,顶多算 “千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个ABABBABA 型的回文日期各是哪一天。
【样例输入】
20200202
【样例输出】
20211202
21211212
【评测用例规模与约定】
对于所有评测用例,10000101 ≤ N ≤ 89991231,保证 N 是一个合法日期的
8 位数表示。
关键在于合法日期的判定,此外题目所给N范围是错的!

int a,b,c,d,e,f,g,h;
bool islegal(){ //合法日期
    int y=h*1000+g*100+f*10+e;
    int m=d*10+c;
    int d=b*10+a;
    if (m==1||m==3||m==5||m==7||m==8||m==10||m==12){ //1 3 5 7 8 10 12
        if (d>0 && d<32) return true;
        else return false;
    }
    if (m==4||m==6||m==9||m==11){//4 6 9 11
        if (d>0 && d<31) return true;
        else return false;
    }
    //平闰年
    int run;
    if (y%100==0){
        if (y%4==0) run=1;
        else run=0;
    }
    else{
        if (y%4) run=1;
        else run=0;
    }
    if (run && m==2 && d>0 && d<=29) return true;
    else if (!run && m==2 && d>0 && d<29) return true;
    else return false;
}
int main(){
    int n,f1=1,f2=1;
    cin>>n;
    while (f1 || f2){
        n+=1;
        //提取每个数字
        a=n%10;
        b=(n/10)%10;
        c=(n/100)%10;
        d=(n/1000)%10;
        e=(n/10000)%10;
        f=(n/100000)%10;
        g=(n/1000000)%10;
        h=(n/10000000)%10;
        if (islegal()){ //合法日期
            if (a==h && b==g && c==f && d==e){
                if (f1){
                    f1=0;
                    cout<<n<<endl;
                }
                if (a==c && b==d){
                    f2=0;
                    cout<<n<<endl;
                }
            }
        }
    }
  return 0;
}

H、子串分值和

对于一个字符串 S,我们定义 S 的分值 f(S) 为 S 中出现的不同的字符个数。例如 f(”aba”) = 2,f(”abc”) = 3, f(”aaa”) = 1。现在给定一个字符串 S[0…n − 1](长度为 n),请你计算对于所有 S 的非空
子串 S[i…j](0 ≤ i ≤ j < n),f(S[i…j]) 的和是多少。
【输入格式】
输入一行包含一个由小写字母组成的字符串 S。
【输出格式】
输出一个整数表示答案。
【样例输入】
ababc
【样例输出】
28
【样例说明】
子串 f值
a 1
ab 2
aba 2
abab 2
ababc 3
b 1
ba 2
bab 2
babc 3
a 1
ab 2
abc 3
b 1
bc 2
c 1
【评测用例规模与约定】
对于 20% 的评测用例,1 ≤ n ≤ 10;
对于 40% 的评测用例,1 ≤ n ≤ 100;
对于 50% 的评测用例,1 ≤ n ≤ 1000;
对于 60% 的评测用例,1 ≤ n ≤ 10000;
对于所有评测用例,1 ≤ n ≤ 100000。
用dp[i][j]表示从i开始j个字符的子串函数值为多少,dp[i][i]=1,而dp[i][j]根据新加入字符与之前有没有重叠=dp[i][j-1] 或dp[i][j-1]+1,动态规划只能骗50%的10分TAT

int main(){
   	string in;
	cin>>in;
	if (in.size()<1000){
		int dp[in.size()][in.size()],k,sum=0; //dp[i][j]:从i截取j个字符的函数值 
		memset(dp,0,sizeof(dp));
		for (int i=0;i<in.size();i++) dp[i][1]=1;
		for (int i=0;i<in.size();i++){
			for (int j=2;j<=in.size()-i;j++){
				for (k=i;k<i+j-1;k++){
					if (in[i+j-1]==in[k]) break;//相同字符 
				}
				if (k<i+j-1) dp[i][j]=dp[i][j-1];
				else dp[i][j]=dp[i][j-1]+1;
				sum += dp[i][j];
			}
		}
		cout<<sum+in.size();
	}
    return 0;
}

对于样例nnehbjgjtkqbbqaaoscajjnpdipsjfrcsbjlkinbsjptrptdfndpoikrqfhrcqamrbptjaahjpsscjnaoqpiqfrncekqacajqhiribrjihadrnddcsespbljsofsiraeeaomblccsorhhmdjchirilssfprgmrcirqblhpfsjcrqgasitgrajpspkhnoqpcgmprlcoblitaolsclqllfgbmijfofbqlfeaqgokscjkimacdingnlistjdnoqcgnggcmnmchneqfqsbeetsphihidmdaojfmhhrallieiqkegdjkctgchnkkfncmoiqohnotrodfcfjjiktljrfikptijbapbijjoqilcdifjrgjafmjdrsfnjnocfbeolnitnlbitsrietiklkfjakojqalnbpteahdfkrojpdsmcsogilhabnjjnndgicdbcssmpmodiehccbidmpdfinhngkageptsnkdjcrecblfpefsqbonbtaprchptoprhfaitjeokptsleqtrknlbfssifohlbqsgrhrslljtchktpcispttarkaoetffqedfdmdgqefsdijtksjrjajhkkbobhlrdooshsedocnskpjmnsbokkbbmphgotprfkpealhonnmpibtnlahcdbphqcnknjtttgdlrdflikgidgnpsmjbnejbsclmdclcigngjljrbpfenslmlmfqioshjjlmeohmaasklhteprbahemsrshrefqnghskbfdcfnejnpfamgaalfkaprrtoofnnddpisjfefgjamjnkjfnghnbrdnljsecnajbssgopndqrmbhosbafgocjhosrknkkclbnjpiotqldjljhmcnkqpapbkmmdcosfpdgddboaerjphjtjckrjcmlmepisjsprbbaeooqtlsgkhsljaikcabgqiggsqbprdporbkieahphfsirhtltmjibqotmqgclnqaosjstifsfehcdgnokcc,应输出9638350。

又是日常膜大佬的一天:
1、每个字母只有在第一次出现时才有贡献度,因此可以统计每个字母在第一次出现的情况下,能被多少子串所包含;
2、用 last[s[i]] 记录字母 s[i] 上一次出现的位置;
3、那么往左最多能延伸到 last[s[i]] + 1,其到第 i 个字母一共有 i - last[s[i]] 个字母;
4、同理往右最多能延伸到 n,其到第 i 个字母一共有 n - i + 1 个字母;
5、二者相乘,就是该字母被不同子串所包含的总次数;

typedef long long ll;
int main(){
    string s;
    cin>>s;
    ll n = s.size(),ans=0,last[2000];
    s = "0"+s;
    for (ll i=1;i<=n;i++){
        ans += (i-last[s[i]])*(n-i+1);
        last[s[i]]=i;
    }
    cout<<ans<<endl;
    return 0;
}

I、平面切分

平面上有 N 条直线,其中第 i 条直线是 y = A i · x + B i 。请计算这些直线将平面分成了几个部分。
【输入格式】
第一行包含一个整数 N。
以下 N 行,每行包含两个整数 A i , B i 。
【输出格式】
一个整数代表答案。
【样例输入】
3
1 1
2 2
3 3
【样例输出】
6
【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ N ≤ 4, −10 ≤ A i , B i ≤ 10。
对于所有评测用例,1 ≤ N ≤ 1000, −100000 ≤ A i , B i ≤ 100000。
在同一个平面内,如果添加的每一条直线互不相交,则每添加一条直线,就会增加一个平面;当添加一条直线时,这条直线与当前平面内已有直线每产生一个不同位置的交点时,这条直线对平面总数量的贡献会额外增多一个。记为S i ,则S i的值为经过该直线的点+1,1为直线自身贡献的平面 , 结果为每一条直线的贡献加上最开始的一个平面,既:S1到Sk的和(k为所有不重合直线的数量)再加上1。

J、字串排序

小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。在冒泡排序中,每次只能交换相邻的两个元素。小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。例如,对于字符串 lan 排序,只需要 1 次交换。对于字符串 qiao 排序,总共需要 4 次交换。小蓝的幸运数字是 V,他想找到一个只包含小写英文字母的字符串,对这个串中的字符进行冒泡排序,正好需要 V 次交换。请帮助小蓝找一个这样的字符串。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。请注意字符串中可以包含相同的字符。
【输入格式】
输入一行包含一个整数 V,为小蓝的幸运数字。
【输出格式】
输出一个字符串,为所求的答案。
【样例输入】
4
【样例输出】
bbaa
【样例输入】
100
【样例输出】
jihgfeeddccbbaa
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ V ≤ 20。
对于 50% 的评测用例,1 ≤ V ≤ 100。
对于所有评测用例,1 ≤ V ≤ 10000。
时间限制: 1.0s 内存限制: 256.0MB 本题总分:25 分
DP大法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值