第十六周往年期末考试题I解题报告
1000. Running Test
题目大意:给出一个人每秒跑多少厘米,输出他跑800米所用秒数(向上取整)
解:单位转换一下,向上取整有标准库函数ceil
题目大意:给出一个人每秒跑多少厘米,输出他跑800米所用秒数(向上取整)
解:单位转换一下,向上取整有标准库函数ceil
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
#define MAXN 1111
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SQR(x) ((x)*(x))
#define EPS (1e-8)
#define WMZ_MAX (2147483647)
int n;
int main(){
cin>>n;
cout << ceil(80000.0/n) << endl;
return 0;
}
1001.
题目大意:判主副对角线元素是否相等的前提下比较主副对角线间元素是否相等(有点绕
解:读懂题后直接判断即可
1002.
题目大意:给出n个数,第一次输出这n个数中的最小值,并把这个数去掉。然后输出n-1个数中的最大值,再把这个数去掉,然后再输出n-2个数中的最小值,如此类推直至没有数为止。
解:其实就是将所有数排序后一左一右输出。
1003.
题目大意:给出两个字符串s1,s2,然后有一个递推关系就是sn=(sn-2) + (sn-1) ,通过这个递推关系生成第k项字符串sk然后计算sk中含有多少个子串"AC",判断个数是否等于题目给予的数值x
解:据说可以暴力做字符串相加然后最后算子串各数。不过其实有更优的办法。我们可以考虑an表示字符串sn里有多少个“AC”,所以an=(an-2)+(an-1)+ ?,这个?是何物呢?考虑这样一个特殊情况 sn-1 == "C.........D",sn-2=="B.......A"
那么sn=sn-2 + sn-1 == "B........AC........D",中间由两个字符串各提供一个字母的AC就是?所表达的意思,因为这个既不在an-1内也不在an-2内,需要我们特判。特判的话我用了一个比较暴力的办法,也是字符串合成,不过我只保存字符串一头一尾两个字符,因为中间的字符已经不可能参与合成出不属于任何一个字符串的“AC”(其实这个好像复杂了,如果你们有更好的特判方法欢迎指出
}
1001.
题目大意:判主副对角线元素是否相等的前提下比较主副对角线间元素是否相等(有点绕
解:读懂题后直接判断即可
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
#define MAXN 1111
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SQR(x) ((x)*(x))
#define EPS (1e-8)
#define WMZ_MAX (2147483647)
//typedef int arr[1000];
int a,b,c,d, n;
int main(){
cin>>n;
while (n--){
scanf("%d%d%d%d", &a, &b, &c, &d);
if (a==d && b==c && a!=b) printf("Yes\n");
else printf("No\n");
}
return 0;
}
1002.
题目大意:给出n个数,第一次输出这n个数中的最小值,并把这个数去掉。然后输出n-1个数中的最大值,再把这个数去掉,然后再输出n-2个数中的最小值,如此类推直至没有数为止。
解:其实就是将所有数排序后一左一右输出。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
#define MAXN 11111
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SQR(x) ((x)*(x))
#define EPS (1e-8)
#define WMZ_MAX (2147483647)
//typedef int arr[1000];
int a[MAXN], n;
int main(){
scanf("%d", &n);
for (int i=1; i<=n; ++i) scanf("%d", &a[i]);
sort(a+1, a+1+n);
int i=1, j=n;
while (i<=j){
if (i==j) printf("%d\n", a[i++]);
else {
printf("%d\n%d\n", a[i++], a[j--]);
}
}
return 0;
} 1003.
题目大意:给出两个字符串s1,s2,然后有一个递推关系就是sn=(sn-2) + (sn-1) ,通过这个递推关系生成第k项字符串sk然后计算sk中含有多少个子串"AC",判断个数是否等于题目给予的数值x
解:据说可以暴力做字符串相加然后最后算子串各数。不过其实有更优的办法。我们可以考虑an表示字符串sn里有多少个“AC”,所以an=(an-2)+(an-1)+ ?,这个?是何物呢?考虑这样一个特殊情况 sn-1 == "C.........D",sn-2=="B.......A"
那么sn=sn-2 + sn-1 == "B........AC........D",中间由两个字符串各提供一个字母的AC就是?所表达的意思,因为这个既不在an-1内也不在an-2内,需要我们特判。特判的话我用了一个比较暴力的办法,也是字符串合成,不过我只保存字符串一头一尾两个字符,因为中间的字符已经不可能参与合成出不属于任何一个字符串的“AC”(其实这个好像复杂了,如果你们有更好的特判方法欢迎指出
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
#define MAXN 11111
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SQR(x) ((x)*(x))
#define EPS (1e-8)
#define WMZ_MAX (2147483647)
int k, x;
long long f[20]={0};
char a[20][500]={0};
int countt(char *a){
int i=0, sum=0;
while (a[i]!=0){
if (a[i]=='A' && a[i+1]=='C'){
++sum;
i+=2;
}
else ++i;
}
i=0;
while (a[i++]!=0);
i--;
if (i-1>=1) a[1]=a[i-1];
else a[1]=a[0];
return sum;
}
int main(){
scanf("%d%d", &k, &x);
scanf("%s", &a[1]);
scanf("%s", &a[2]);
f[1]=countt(a[1]);
f[2]=countt(a[2]);
for (int i=3; i<=k; ++i) {
if (a[i-2][1]=='A' && a[i-1][0]=='C') f[i]++;
a[i][0]=a[i-2][0];
a[i][1]=a[i-1][1];
f[i]+=f[i-2]+f[i-1];
}
if (f[k]==x) printf("Accepted\n");
else printf("Forever alone\n");
return 0;
}
1004.
题目大意:求一个环上某个点到达另一个点上的最小费用。
解:其实一个环上两个点之间的联通方案只有两种,一种顺时针,一种逆时针,直接暴力算即可。
1005
题目大意:将一个字符串内相同且连续x个的字母A压缩为Ax输出(x>1
解:模拟即可,用多一个指针指向当前字母的下一个判断是否相等,若相等就不对增加并统计相等数即可。统计完记得将当前指针i跳过当前这一段。
1004.
题目大意:求一个环上某个点到达另一个点上的最小费用。
解:其实一个环上两个点之间的联通方案只有两种,一种顺时针,一种逆时针,直接暴力算即可。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
#define MAXN 11111
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SQR(x) ((x)*(x))
#define EPS (1e-8)
#define WMZ_MAX (2147483647)
int n, a[111], sum, st, ed, ans;
int main(){
scanf("%d", &n);
sum=0;
for (int i=1; i<=n; ++i) {
scanf("%d", &a[i]);
sum+=a[i];
}
scanf("%d%d", &st, &ed);
if (st>ed) swap(st, ed);
ans=0;
for (int i=st; i<ed; ++i) ans+=a[i];
if (ans<sum-ans) printf("%d\n", ans);
else printf("%d\n", sum-ans);
return 0;
}
1005
题目大意:将一个字符串内相同且连续x个的字母A压缩为Ax输出(x>1
解:模拟即可,用多一个指针指向当前字母的下一个判断是否相等,若相等就不对增加并统计相等数即可。统计完记得将当前指针i跳过当前这一段。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
#define MAXN 11111
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SQR(x) ((x)*(x))
#define EPS (1e-8)
#define WMZ_MAX (2147483647)
char a[111111];
int main(){
int i, j;
while (scanf("%s", a)==1){
for (int i=0; a[i]!=0; ++i){
printf("%c", a[i]);
int j=i+1;
while (a[j]==a[i]) ++j;
if (j-i>1) {
printf("%d", j-i);
i=j-1;
}
}
printf("\n");
}
return 0;
}
1006.
题目大意:有三个基佬想一起打lol,他们为了开五人黑还得凑两个妹子。给出三个基佬有空的时间段,和若干个妹子有空的时间段,问一天内是哪些可以开一局lol的时间段(任意来两个妹子即可,但是三个基佬一定都要到齐。同时每个人自己的时间段不会重叠
解:可以发现,一天只有8万多秒,所以可以转化为一个染色问题。把时间段从三维向量(时,分,秒)映射到一维向量上(秒),然后每秒询问有多少个人可以玩(是否有三个基佬和两个及以上的妹子有空)貌似逐秒将所有的时间段都check一次是否包含这一秒的复杂度能过,但是这题能过优化优化在优化:
优化1:(其中用了一个我称为倍差法的细节),想涂油漆一样,先声明一个八万左右大小的数组,有一个人在[x,y]时间段上有空的话就往[x,y)的格子上赋值。然后全部时间段像刷油漆一样全部刷完后,怎么判断某个格子是否能凑齐人呢?
从题目条件发现,妹子数不会大于100,那么我们以100为倍差约定,妹子权重为1,第一基佬权重为100,第二基佬权重为10000,第三基佬权重为1000000,那么刷油漆赋值的时候直接加到格子上。然后从头开始查询每一秒是否符合条件时我们读取这个权重和,如果权值为1010103,说明这一秒有三个妹子,第一第二第三基佬都有空。而如果是1000101,说明他们第二基佬没空以及少一个妹子。
(PS,这个优化复杂度貌似是和暴力无区别(会退化),只是常数更小
优化2:
这玩意叫差分序列。。。。。有点像导数的思想。我也不知道怎么说,想学的话琢磨我的程序,有不懂的直接来问我
1007.
题目大意:给出一个矩阵,你可以对当中的元素进行+-d操作,问是否能通过若干次操作使得所有数一样,
解:我是暴力做,枚举答案,看是否能操作,如果能则记录方案数,不能则输出-1。当然有更快的做法。首先先判断是否有解(元素两两间之差一定为d的倍数),然后找到最小值则是一个经典问题,等于数轴上找一个值使得它两边的点的个数最多且只相差一个。想专精的同学可以推导做一下。
旧题了请去翻以前的解题报告
1009.
题目大意:把每个数左边第一个比它大的数的编号全部加起来输出
解:首先强调一下答案要用longlong保存。然后做法是用一个栈来优化即可将时间复杂度做到O(n){其实有些同学用链表维护道理是差不多的只是可能栈我觉得更直观}。首先栈内元素是单调递减的,也就是说从栈底向栈顶单调递减。如果当前这个数比栈顶小,那么栈顶元素即是左边第一个比他大的元素。否则栈顶元素退栈直到栈顶元素比当前数大或者栈为空(或者假设一个超级大的数一开始放入栈,设定他的位置为0,这样就不需要特判栈是否为空了)。然后栈顶元素就是第一个比现在大的元素。最后当前元素入栈。退栈过程其实是将一些无用的选择去除(因为如果前面的数比当前的数还小,那么他们不可能成为后面第一个比后面的数大的数。所以栈里保存的是所有可能成为答案的数。而因为每个数只会进栈和退栈一次。所以时间复杂度是O(n)
1006.
题目大意:有三个基佬想一起打lol,他们为了开五人黑还得凑两个妹子。给出三个基佬有空的时间段,和若干个妹子有空的时间段,问一天内是哪些可以开一局lol的时间段(任意来两个妹子即可,但是三个基佬一定都要到齐。同时每个人自己的时间段不会重叠
解:可以发现,一天只有8万多秒,所以可以转化为一个染色问题。把时间段从三维向量(时,分,秒)映射到一维向量上(秒),然后每秒询问有多少个人可以玩(是否有三个基佬和两个及以上的妹子有空)貌似逐秒将所有的时间段都check一次是否包含这一秒的复杂度能过,但是这题能过优化优化在优化:
优化1:(其中用了一个我称为倍差法的细节),想涂油漆一样,先声明一个八万左右大小的数组,有一个人在[x,y]时间段上有空的话就往[x,y)的格子上赋值。然后全部时间段像刷油漆一样全部刷完后,怎么判断某个格子是否能凑齐人呢?
从题目条件发现,妹子数不会大于100,那么我们以100为倍差约定,妹子权重为1,第一基佬权重为100,第二基佬权重为10000,第三基佬权重为1000000,那么刷油漆赋值的时候直接加到格子上。然后从头开始查询每一秒是否符合条件时我们读取这个权重和,如果权值为1010103,说明这一秒有三个妹子,第一第二第三基佬都有空。而如果是1000101,说明他们第二基佬没空以及少一个妹子。
(PS,这个优化复杂度貌似是和暴力无区别(会退化),只是常数更小
优化2:
这玩意叫差分序列。。。。。有点像导数的思想。我也不知道怎么说,想学的话琢磨我的程序,有不懂的直接来问我
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAXT 86400
#define LIM 62
int a[MAXT+11];
int len[4];
int change(int a, int b, int c){
return a*3600 + b*60 + c;
}
void rechange(int x){
printf("%02d:%02d:%02d", x/3600, x/60%60, x%60);
}
void get(int add){
int b, c, d, x, y, z;
scanf("%d:%d:%d %d:%d:%d", &b, &c, &d, &x, &y, &z);
int i=change(b, c, d);
a[i]+=add;
i=change(x, y, z);
a[i]+=-add;
}
int main(){
bool flag;
int cas=0, tmp, n, m;
while (scanf("%d%d%d", &len[1], &len[2], &len[3])==3){
flag=true;
cas++; if (cas>1) printf("\n");
memset(a, 0, sizeof(a));
for (int i=1; i<=3; ++i){
for (int j=1; j<=len[i]; ++j) get(i*10);
}
scanf("%d", &tmp);
for (int i=1; i<=tmp; ++i){
scanf("%d", &n);
for (int i=1; i<=n; ++i) get(1);
}
for (int i=1; i<MAXT; ++i){
a[i]+=a[i-1];
}
for (int i=0; i<MAXT; ++i){
if (a[i]>=LIM){
flag=false;
int j=i;
while (a[j]>=LIM) {
j++;
}
rechange(i); printf(" "); rechange(j); printf("\n");
i=j;
}
}
if (flag) printf("You cannot start a game!\n");
}
return 0;
}
1007.
题目大意:给出一个矩阵,你可以对当中的元素进行+-d操作,问是否能通过若干次操作使得所有数一样,
解:我是暴力做,枚举答案,看是否能操作,如果能则记录方案数,不能则输出-1。当然有更快的做法。首先先判断是否有解(元素两两间之差一定为d的倍数),然后找到最小值则是一个经典问题,等于数轴上找一个值使得它两边的点的个数最多且只相差一个。想专精的同学可以推导做一下。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
#define MAXN 1111111
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SQR(x) ((x)*(x))
#define EPS (1e-8)
#define WMZ_MAX (2147483647)
#define LOWBIT(x) ((x)&(-x))
int n, m, d, ans, mid;
int a[111][111];
int check(){
int sum=0;
for (int i=1; i<=n; ++i)
for (int j=1; j<=m; ++j)
if (abs(mid-a[i][j])%d==0){
sum+=abs(mid-a[i][j])/d;
if (sum>ans) return -1;
}
else return -1;
return sum;
}
int main(){
scanf("%d%d%d", &n, &m, &d);
for (int i=1; i<=n; ++i)
for (int j=1; j<=m; ++j) scanf("%d", &a[i][j]);
ans=2147483647;
for (mid=1; mid<=10000; ++mid){
int tmp=check();
if (tmp>0 && tmp<ans) ans=tmp;
}
if (ans==2147483647) ans=-1;
cout << ans << endl;
return 0;
}
1008.
旧题了请去翻以前的解题报告
1009.
题目大意:把每个数左边第一个比它大的数的编号全部加起来输出
解:首先强调一下答案要用longlong保存。然后做法是用一个栈来优化即可将时间复杂度做到O(n){其实有些同学用链表维护道理是差不多的只是可能栈我觉得更直观}。首先栈内元素是单调递减的,也就是说从栈底向栈顶单调递减。如果当前这个数比栈顶小,那么栈顶元素即是左边第一个比他大的元素。否则栈顶元素退栈直到栈顶元素比当前数大或者栈为空(或者假设一个超级大的数一开始放入栈,设定他的位置为0,这样就不需要特判栈是否为空了)。然后栈顶元素就是第一个比现在大的元素。最后当前元素入栈。退栈过程其实是将一些无用的选择去除(因为如果前面的数比当前的数还小,那么他们不可能成为后面第一个比后面的数大的数。所以栈里保存的是所有可能成为答案的数。而因为每个数只会进栈和退栈一次。所以时间复杂度是O(n)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <cmath>
using namespace std;
#define MAXN 1111111
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SQR(x) ((x)*(x))
#define EPS (1e-8)
#define WMZ_MAX (2147483647)
#define LOWBIT(x) ((x)&(-x))
int n, a[MAXN];
int lab[MAXN], ans, tot;
long long t[MAXN];
int main(){
int cas;
t[0]=2147483647*2;
lab[0]=0;
scanf("%d",&cas);
while (cas--){
scanf("%d", &n);
for (int i=1; i<=n; ++i) scanf("%d", &a[i]);
long long ans=0;
tot=1;
t[tot]=a[1]; lab[tot]=1;
for (int i=2; i<=n; ++i){
while (tot && a[i]>t[tot]) tot--;
ans+=lab[tot];
tot++;
t[tot]=a[i]; lab[tot]=i;
}
cout << ans << endl;
}
return 0;
}