大庆市中学生计算机技术应用能力大赛
emmmmm虽然分还没出就瞎几把写一写蒟蒻的思路
第一题:遭遇战
【问题描述】
小林和小华在一个 n×n 的矩形方格里玩游戏,矩形左上角为(0,0),右下角为(n-1,n-1)。
两人同时进入地图的随机位置,并以相同速度进行走位。为了隐蔽性,两人都不会再走自己走过的格子。如果两人向某一方向前进,那么他们会跑到不能跑为止,当不能跑的时候,小林会向右转,小华则会向左转,如果不能跑,则不再动。现在已知两人进入地图的初始位置和方向,请算出两人遭遇的位置。
【输入格式】
第 1 行 1 个正整数 t,表示测试数据组数,\(1≤t≤10\)。
接下来的 t 组数据,每组数据的第 1 行包含 1 个整数 n,\(1≤n≤1000\)。
第 2 行包含 3 个整数 x、y 和 d,表示小林的初始位置和一开始跑的方向。其中,d=0 表示东; d=1 表示南;d=2 表示西;d=3 表示北。
第 3 行与第 2 行格式相同,但描述的是小华。
【输出格式】
输出 t 行,若会遭遇,则包含两个整数,表示他们第一次相遇格子的坐标,否则输出“-1”。
【输入样例】
2
2
0 0 0
0 1 2
4
0 1 0
3 2 0
【输出样例】
-1
1 3
蒟蒻只想出了爆搜。。。贴代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1010
using namespace std;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};//方向
int t,n,x,y,d,x1,y1,d1;
bool a[maxn][maxn],b[maxn][maxn];//记录小林和小华走过的地方
void dfs()
{
bool f1=true,f2=true;
while((x!=x1)||(y!=y1)){//搜到两人相遇或走不了了
if(f1){//小林还能走
int j=x+dx[d],k=y+dy[d];//移动
if(!a[j][k]){//没走过
d=(d+1)%4;
j=x+dx[d];
k=y+dy[d];//走
if(!a[j][k]){//打标记
f1=false;
}
}
if(f1){//小林还能走
x=j;
y=k;
a[j][k]=false;//打标记
}
}
if(f2){//小华还能走同小林
int j=x1+dx[d1],k=y1+dy[d1];
if(!b[j][k]){
d1=(d+3)%4;
j=x1+dx[d1];
k=y1+dy[d1];
if(!b[j][k]){
f2=false;
}
}
if(f2){
x1=j;
y1=k;
b[j][k]=false;
}
}
if((!f1)&&(!f2)){
break;
}
}
if((x==x1)&&(y==y1)){//相遇了
printf("%d %d\n",x,y);
}
else{//没相遇
printf("-1\n");
}
return;
}
int main()
{
scanf("%d",&t);
for(int i=1;i<=t;i++){
scanf("%d",&n);
scanf("%d%d%d%d%d%d",&x,&y,&d,&x1,&y1,&d1);
memset(a,false,sizeof(a));
memset(b,false,sizeof(b));
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
a[j][k]=true;
b[j][k]=true;//初始化
}
}
dfs();
}
return 0;
}
是真的暴力,,,手动滑稽
第二题 保龄球
【问题描述】
打保龄球是用一个滚球去打击十个站立的柱,将柱击倒。一局分十轮,每轮可滚球一次或多次,以击倒的柱数为依据计分。一局得分为十轮得分之和,而每轮的得分不仅与本轮滚球情况有关,还可能与后续一两轮的滚球情况有关。即某轮某次滚球击倒的柱数不仅要计入本轮得分,还可能会计入前一两轮得分。具体的滚球击柱规则和计分方法如下:
(1) 若某一轮的第一次滚球就击倒全部十个柱,则本轮不再滚球(若是第十轮则还需另加两次滚球,不妨称其为第十一轮和第十二轮,并不是所有的情况都需要滚第十一轮和第十二轮球)。该轮得分为本次击倒柱数 10 与以后两次滚球所击倒柱数之和。
( 2) 若某一轮的第一次滚球未击倒十个柱,则可对剩下未倒的柱再滚球一次。如果这两次滚球击倒全部十个柱,则本轮不再滚球(若是第十轮则还需另加一次滚球),该轮得分为这两次共击倒柱数 10 与以后一次滚球所击倒柱数之和。
(3) 若某一轮两次滚球未击倒全部十个柱,则本轮不再继续滚球,该轮得分为这两次滚球击倒的柱数之和。
总之,若某一轮中一次滚球或两次滚球击倒十个柱,则本轮得分是本轮首次滚球开始的连续三次滚球击倒柱数之和(其中有一次或两次不是本轮滚球)。若一轮内二次滚球击倒柱数不足十个,则本轮得分即为这两次击倒柱数之和。下面以实例说明如下:
轮 1 2 3 4 5 6 7 8 9 10 11 12
击球情况 / / / 72 9/ 81 8/ / 9/ / 8/
各轮得分 30 27 19 9 18 9 20 20 20 20
累计总分 30 57 76 85 103 112 132 152 172 192
现在请编写一个保龄球计分程序,用来计算并输出最后的总得分。
【输入格式】
输入一行,为前若干轮滚球的情况,每轮滚球用一到两个字符表示,每一个字符表示一次击球,字符“/”表示击倒当前球道上的全部的柱,否则用一个数字字符表示本次滚球击倒的当前球道上的柱的数目,两轮滚球之间用一个空格隔开。
【输出格式】
输出一行一个整数,代表最后的得分。
【输入样例 1】
/ / / 72 9/ 81 8/ / 9/ / 8/
【输出样例 1】
192
【输入样例 2】
90 90 / 9/ 81 / / / 72 / /0
【输出样例 2】
170
【输入样例 3】
/ / / 72 9/ 81 8/ / 9/ 15
【输出样例 3】
169
这题。。。不会打保龄球。。。直接模拟。。。贴代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define maxn 100
using namespace std;
int main()
{
//freopen("read.txt","r",stdin);
char c,st[maxn];
int ans=0,cur=0,cnt=0;
while(~scanf("%c",&c)){//毒瘤输入
if(c!=' '){
st[++cur]=c;//只要有用的
}
}
for(int i=1,j=1;i<=10;i++){//很一般的模拟
if(st[j]=='/'){
cnt=10;
if(st[j+1]=='/'){
cnt+=10;
if(st[j+2]=='/'){
cnt+=10;
}
else{
cnt+=st[j+2]-'0';
}
}
else{
if(st[j+2]=='/'){
cnt+=10;
}
else{
cnt+=st[j+1]-'0'+st[j+2]-'0';
}
}
j+=1;
}
else{
if(st[j+1]=='/'){
if(st[j+2]=='/'){
cnt=20;
}
else{
cnt=10+st[j+2]-'0';
}
}
else{
cnt=st[j]-'0'+st[j+1]-'0';
}
j+=2;
}
ans+=cnt;
}
printf("%d\n",ans);
return 0;
}
你看就非常的暴力
第三题 同花顺
题目描述
所谓同花顺,就是指一些扑克牌,它们花色相同,并且数字连续。
现在我手里有n 张扑克牌,但它们可能并不能凑成同花顺。我现在想知道,最
少更换其中的多少张牌,我能让这n 张牌凑成一个同花顺?
输入格式
第一行一个整数n,表示扑克牌的张数。
接下来n 行,每行两个整数\(a_i\) 和\(b_i\)。其中\(a_i\) 表示第i 张牌的花色,\(b_i\) 表示第
i 张牌的数字。
(注意:这里的牌上的数字不像真实的扑克牌一样是1 到13,具体见数据范围)
输出格式
一行一个整数,表示最少更换多少张牌可以达到目标。
样例输入1
5
1 1
1 2
1 3
1 4
1 5
样例输出1
0
样例输入2
5
1 9
1 10
2 11
2 12
2 13
样例输出2
2
数据范围
对于30% 的数据,n ≤ 10。
对于60% 的数据,\(n ≤ 10^5,1 ≤ a_i ≤ 10^5,1 ≤ b_i ≤ n\)。
对于100% 的数据,\(n ≤ 10^5\),\(1 ≤ a_i, bi ≤ 10^9\)。
找一段同花上升子序列。。。贴代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,ans,cnt;//最长序列长度,计数器
struct node{
int col,num;//花色大小
}a[100010],q[100010];
int cmp(node x,node y){//按花色和大小排顺序
if(x.col==y.col){
return x.num<y.num;
}
return x.col<y.col;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i].col,&a[i].num);
}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
if(a[i].col==a[i-1].col&&a[i].num==a[i-1].num){
continue;
}
q[++cnt]=a[i];
}
for(int i=1;i<=cnt;i++){
int tmp=0;
for(int j=i;j>=1;j--){
if((q[j].col==q[i].col)&&(q[i].num-q[j].num+1<=n)){
tmp++;//去重
}
else break;
}
ans=max(ans,tmp);
}
printf("%d",n-ans);
return 0;
}
第四题 拯救世界
题目描述
C 城所有的道路都是单向的。不同道路之间有路口,每个路口都有一个大楼。有一天,城市里的所有大楼因为不明原因,突然着火了。作为超人的你要去拯救
这些大楼。初始的时候你在S 号楼,最后你必须到达某个有补给站的大楼,你可以
沿着单向道路行驶。你可以经过某条道路或者某个大楼若干次,经过一个大楼你就
可以消灭一个大楼的大火。每个大楼都有一个重要程度,最后这个任务的评价分数
就是你经过的所有大楼的重要度之和(若重复经过某个大楼多次,则不重复算分)。
你是一个聪明的超人,你想知道,通过合理的规划路线,你这次任务能得到的
最高得分是多少。
注意,该城市的道路可能有重边或自环。
输入格式
第一行包括两个整数n,m,n 表示路口的个数(即大楼的个数),m 表示道路
的条数。
接下来m 行,每行两个整数x; y,表示x 到y 之间有一条单向道路。
接下来n 行,每行一个整数,按顺序表示每个大楼的重要度。
接下来一行包含两个整数S 和P,S 是出发的路口(大楼)的编号,P 是有补
给站的大楼的数量。
接下来一行P 个整数,表示有补给站的大楼的编号。
输出格式
输出一行一个整数,表示你得分的最大值。
样例输入1
6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1
5
1 4
4 3 5 6
样例输出1
47
数据范围
对于1、2、3 测试点,N;M ≤ 300
对于4、5、6、7、8、9、10 测试点,N;M≤ 3000
对于11、12、13、14、15 测试点,N;M ≤ 500000。每个大楼的重要度均为非
负数且不超过4000。
输入数据保证你可以从起点沿着单向道路到达其中的至少一个有补给站的大
楼。
注意,输入数据中存在树和链的特殊情况
终于没有暴力的最后一题。。。太监缩点+最短路(SPFA考试时忘了所以用的dfs估计要超时)
代码码住
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500050
using namespace std;
int n,m,num,head[maxn],head1[maxn],w[maxn],t[maxn],s,cur,w1[maxn];
int ans=0;
struct node{
int to,pre;
}e[maxn],e1[maxn];//邻接表
void ins(int from,int to){//加边
e[++num].to=to;
e[num].pre=head[from];
head[from]=num;
}
int dfn[maxn],low[maxn],st[maxn],bel[maxn];
bool instr[maxn];
int nums,cnt,numtj;
void tarjan(int u){//太监缩点,因为一个强连通分量内所有的点都能到达,所以当一个处理
cnt++;
st[++nums]=u;
dfn[u]=low[u]=cnt;
instr[u]=1;
for(int i=head[u];i;i=e[i].pre){
int v=e[i].to;
if(!dfn[v]){
tarjan(v);
if(low[v]<low[u]){
low[u]=low[v];
}
}
else if(dfn[v]<low[u])
if(instr[v])
low[u]=dfn[v];
}
if(dfn[u]==low[u]){
numtj++;
while(st[nums]!=u){
instr[st[nums]]=0;
bel[st[nums]]=numtj;
nums--;
}
instr[u]=0;
nums--;
bel[u]=numtj;
}
}
void ins2(int from,int to){//加边
e1[++cur].to=to;
e1[cur].pre=head1[from];
head1[from]=cur;
}
bool ok[maxn];
void dfs(int now,int sum){//深搜
if(ok[now]){
ans=max(ans,sum);
}
for(int i=head1[now];i;i=e1[i].pre){
int to=e1[i].to;
dfs(to,sum+w1[to]);
}
}
int main(){
scanf("%d%d",&n,&m);
int x,y;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
ins(x,y);//建图
}
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
}
int numt;
scanf("%d%d",&s,&numt);
for(int i=1;i<=numt;i++){
scanf("%d",&t[i]);
}
for(int i=1;i<=n;i++){
if(!dfn[i]){
tarjan(i);//缩点
}
}
for(int now=1;now<=n;now++){
w1[bel[now]]+=w[now];
for(int i=head[now];i;i=e[i].pre){
int to=e[i].to;
if(bel[now]!=bel[to]){
ins2(bel[now],bel[to]);
}
}
}
for(int i=1;i<=numt;i++){
ok[bel[t[i]]]=1;
}
ans=w1[bel[s]];
dfs(bel[s],w1[bel[s]]);//爆搜
printf("%d",ans);
return 0;
}