7-1 数列查询 (100 分)
已知数列的通项公式为:
f(n) = f(n-1)*11/10,f[1]=10.
通项从左向右计算,*和/分别表示整数乘法和除法。 现在,要多次查询数列项的值。
输入格式:
第1行,1个整数q,表示查询的次数, 1≤q≤10000. 第2至q+1行,每行1个整数i,表示要查询f(i)的值。
输出格式:
q行,每行1个整数,表示f(i)的值。查询的值都在32位整数范围内。
输入样例:
在这里给出一组输入。例如:
3
1
2
3
输出样例:
在这里给出相应的输出。例如:
10
11
12
题目分析
即考察记忆化搜索。
代码实现如下
#include<stdio.h>
int a[10000];
int f(int n){
if(n==1) return a[1];
else {
if(a[n]!=0)return a[n];
else {a[n]=f(n-1)*11/10;return a[n];}
}
}
int main(){
int q,k;
scanf("%d",&q);
a[1]=10;
for(int i=1;i<=q;i++){
scanf("%d",&k);
printf("%d\n",f(k));
}
return 0;
}
7-2 稀疏矩阵之和 (100 分)
矩阵A和B都是稀疏矩阵。请计算矩阵的和A+B.如果A、B不能做和,输出“Illegal!”
输入格式:
矩阵的输入采用三元组表示,先A后B。对每个矩阵:
第1行,3个整数N、M、t,用空格分隔,分别表示矩阵的行数、列数和非0数据项数,10≤N、M≤50000,t≤min(N,M).
第2至t+1行,每行3个整数r、c、v,用空格分隔,表示矩阵r行c列的位置是非0数据项v, v在32位有符号整型范围内。三元组默认按行列排序。
输出格式:
矩阵A+B,采用三元组表示,默认按行列排序,非零项也在32位有符号整型范围内。
输入样例:
10 10 3
2 2 2
5 5 5
10 10 20
10 10 2
2 2 1
6 6 6
输出样例:
10 10 4
2 2 3
5 5 5
6 6 6
10 10 20
题目分析
即考察三元组表的相关操作。值得注意的是,若合并后值为0,则舍弃该节点。
代码实现如下
#include<stdio.h>
#include<stdlib.h>
typedef struct ju{
int r,c,v;
}ju;
ju a[50010],b[50010],c[110000];
int main(){
int Ma,Na,ta,Mb,Nb,tb,topa=0,topc=0,flag=1;
scanf("%d %d %d",&Ma,&Na,&ta);
for(int i=0;i<ta;i++){
scanf("%d %d %d",&a[i].r,&a[i].c,&a[i].v);
}
scanf("%d %d %d",&Mb,&Nb,&tb);
for(int i=0;i<tb;i++){
scanf("%d %d %d",&b[i].r,&b[i].c,&b[i].v);
if(topa!=ta){
if(a[topa].r==b[i].r&&a[topa].c==b[i].c){
c[topc].r=a[topa].r;
c[topc].c=a[topa].c;
c[topc].v=a[topa].v+b[i].v;
topa++;
topc++;
if(c[topc-1].v==0){
topc--;
}
continue;
}
else
while(topa!=ta){
if(a[topa].r<b[i].r){
c[topc].r=a[topa].r;
c[topc].c=a[topa].c;
c[topc].v=a[topa].v;
topa++;
topc++;
}
else if(a[topa].r==b[i].r&&a[topa].c<b[i].c){
c[topc].r=a[topa].r;
c[topc].c=a[topa].c;
c[topc].v=a[topa].v;
topa++;
topc++;
}
else break;
}
}
c[topc].r=b[i].r;
c[topc].c=b[i].c;
c[topc].v=b[i].v;
topc++;
}
while(topa!=ta){
c[topc].r=a[topa].r;
c[topc].c=a[topa].c;
c[topc].v=a[topa].v;
topa++;
topc++;
}
if(Ma!=Mb||Na!=Nb){printf("Illegal!");return 0;}
printf("%d %d %d\n",Ma,Na,topc);
for(int i=0;i<topc;i++){
printf("%d %d %d\n",c[i].r,c[i].c,c[i].v);
}
return 0;
}
7-3 文字编辑 (100 分)
一篇文章由n个汉字构成,汉字从前到后依次编号为1,2,……,n。 有四种操作:
A i j表示把编号为i的汉字移动编号为j的汉字之前;
B i j表示把编号为i的汉字移动编号为j的汉字之后;
Q 0 i为询问编号为i的汉字之前的汉字的编号;
Q 1 i为询问编号为i的汉字之后的汉字的编号。
规定:1号汉字之前是n号汉字,n号汉字之后是1号汉字。
输入格式:
第1行,1个整数T,表示有T组测试数据, 1≤T≤9999.
随后的每一组测试数据中,第1行两个整数n和m,用空格分隔,分别代表汉字数和操作数,2≤n≤9999,1≤m≤9999;第2至m+1行,每行包含3个常量s、i和j,用空格分隔,s代表操作的类型,若s为A或B,则i和j表示汉字的编号,若s为Q,i代表0或1,j代表汉字的编号。
输出格式:
若干行,每行1个整数,对应每个询问的结果汉字编号。
输入样例:
在这里给出一组输入。例如:
1
9999 4
B 1 2
A 3 9999
Q 1 1
Q 0 3
输出样例:
在这里给出相应的输出。例如:
4
9998
题目分析
我手写了一个双端队列,每次操作更改前驱后继即可。
代码实现如下
#include<stdio.h>
struct po{
int fo,next;
}a[10000];
int Q(struct po *a,int k,int i){
if(k==1)return a[i].next;
else if(k==0)return a[i].fo;
}
void take_front(struct po *a,int i,int j){
int r,t,k,n;
if(a[i].next==j)return;
if(a[j].next!=i){
r=a[i].fo;
k=a[i].next;
n=a[j].fo;
t=a[j].next;
//
a[r].next=k;
a[k].fo=r;
//
a[n].next=i;
a[i].fo=n;
a[j].fo=i;
a[i].next=j;
}
else {
k=a[i].next;
n=a[j].fo;
//
a[k].fo=j;
a[j].next=k;
a[j].fo=i;
a[i].next=j;
a[i].fo=n;
a[n].next=i;
}
return ;
}
void take_back(struct po *a,int i,int j){
int r,t,k,n;
if(a[j].next==i)return;
if(a[i].next!=j){
r=a[i].fo;
k=a[i].next;
t=a[j].next;
//
a[r].next=k;
a[k].fo=r;
//
a[i].fo=j;
a[j].next=i;
a[i].next=t;
a[t].fo=i;
}
else {
r=a[i].fo;
t=a[j].next;
//
a[r].next=j;
a[j].fo=r;
a[i].fo=j;
a[j].next=i;
a[i].next=t;
a[t].fo=i;
}
return ;
}
int main(){
int t,n,m,i,j,x,y;
char ran;
scanf("%d",&t);
for(i=0;i<t;i++){
scanf("%d %d",&n,&m);
a[n].next=1;a[1].fo=n;
for(j=1;j<n;j++){a[j].next=j+1;a[j+1].fo=j;}
for(j=0;j<m;j++){
scanf("\n%c%d%d",&ran,&x,&y);
if(ran=='Q')printf("%d\n",Q(a,x,y));
else if(ran=='A')take_front(a,x,y);
else if(ran=='B')take_back(a,x,y);
}
}
return 0;
}
7-4 幸福指数 (100 分)
人生中哪段时间最幸福?幸福指数可能会帮你发现。幸福指数要求:对自己每天的生活赋予一个幸福值,幸福值越大表示越幸福。一段时间的幸福指数就是:这段时间的幸福值的和乘以这段时间的幸福值的最小值。幸福指数最大的那段时间,可能就是人生中最幸福的时光。
输入格式:
第1行,1个整数n,, 1≤n≤100000,表示要考察的天数。
第2行,n个整数Hi,用空格分隔,Hi表示第i天的幸福值,0≤n≤1000000。
输出格式:
第1行,1个整数,表示最大幸福指数。
第2行,2个整数l和r,用空格分隔,表示最大幸福指数对应的区间[l,r]。如果有多个这样的区间,输出最长最左区间。
输入样例:
在这里给出一组输入。例如:
7
6 4 5 1 4 5 6
输出样例:
在这里给出相应的输出。例如:
60
1 3
题目分析
此题即枚举n种情况:每一个值作为区间最小值,计算区间和与之的乘积,得数最大的就是所求区间。使用一个单调栈,求出每个以该值最为最小值的区间的左边界与右边界即可。
代码实现如下
#include <stdio.h>
int a[100010];
long long b[100010];
int l[100010],r[100010];
int queuel[100010],queuer[100010];
int INF = 1e9;
int main(){
int n,i,k,topl=0,topr=0;
scanf("%d",&n);
a[0]=a[n+1]=-INF;
for(i=1;i<=n;i++){
scanf("%d",&k);
a[i]=k;
b[i]=a[i]+b[i-1];
}
queuel[0]=0;
for(i=1;i<=n;i++){
while(a[queuel[topl]]>=a[i])topl--;
l[i]=queuel[topl];
queuel[++topl]=i;
}
queuer[0]=n+1;
for(i=n;i>=1;i--){
while(a[queuer[topr]]>=a[i])topr--;
r[i]=queuer[topr];
queuer[++topr]=i;
}
long long max=0;
int l0,r0;
for(i=1;i<=n;i++){
long long t;
t=a[i]*(b[r[i]-1]-b[l[i]]);
if(t>max){
max=t;
l0=l[i]+1;
r0=r[i]-1;
}
else if(t==max){
if(r[i]-l[i]-2>r0-l0){
l0=l[i]+1;
r0=r[i]-1;
}
else if(l[i] + 1 <l0){
l0=l[i]+1;
r0=r[i]-1;
}
}
}
printf("%lld\n%d %d\n",max,l0,r0);
return 0;
}