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、序列计数
小明想知道,满足以下条件的正整数序列的数量:
- 第一项为 n;
- 第二项不超过 n;
- 从第三项开始,每一项小于前两项的差的绝对值。
请计算,对于给定的 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。
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大法