题目说明:

E、F、G、I是我出的
B、C、H、J是任泓润出的
A、B、K、L是杨宇出的

A.善良的杨宇

解题思路

差分,然后找连续的值大于0的最长可能,具体看代码

code

#include 
using namespace std;
const int N = 100005;

int a[N];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1;i <= n; ++i) {
        scanf("%d",&a[i]);
    }
    for(int i = n;i >= 1; --i)
        a[i] -= a[i-1];
    int loc = 0;
    int ans = 0;
    for(int i = 1;i <= n; ++i) {
        if(a[i] > 0) {
            loc++;
        }
        else {
            ans = max(ans,loc);
            loc = 1;
        }
    }
    ans = max(ans,loc);
    printf("%d\n",ans);
    return 0;
}

B.芜湖!加速!

解题思路

因为普通搜索时,我们有时可能会用到之前所搜索到的结果,这时如果我们再次搜索就显得没有必要了(会浪费很多时间呢),所以如果我们已经记录了之前搜索的答案不就可以直接用之前的搜索答案了么

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 500;//数据并不大
const int dx[]= {0,0,1,-1};
const int dy[]= {1,-1,0,0};
int r,c,ans;
int map[maxn][maxn],step[maxn][maxn];
int dfs(int x,int y) {
    if(step[x][y]) return step[x][y];//一开始每个点的步数都应为0;如果当前这个点已知其最大步数说明之前该点已被计算过就不用再重复计算了(这不是废话么- -||);
    step[x][y]=1;//既然这是一个从未走过的点那么现在来到该点至少都会使其步数为1
    for(int i=0; i<4; i++) { //四个可行的方向
        int nx=x+dx[i],ny=y+dy[i];
        if(map[nx][ny]<map[x][y]) {
            step[x][y]=max(step[x][y],1+dfs(nx,ny));//代码核心
        }
    }
    return step[x][y];//返回值给上一个dfs调用
}
int main() {
    ios::sync_with_stdio(false);
    scanf("%d%d",&r,&c);
    //初始化处理
    for(int i=0; i<=c+1; i++) { //将边界的高度设为无限高这样就免去了判断是否超出地图限制
        map[i][0]=map[i][c+1]=1e9;
    }
    for(int i=0; i<=r+1; i++) {
        map[0][i]=map[r+1][i]=1e9;
    }
    //读入每个点的数据
    for(int i=1; i<=r; i++) {
        for(int j=1; j<=c; j++) {
            scanf("%d",&map[i][j]);
        }
    }
    for(int i=1; i<=r; i++) {
        for(int j=1; j<=c; j++) {
            ans=max(dfs(i,j),ans);//每一个点都跑一边dfs,答案取最大的就是题目要求了
        }
    }
    cout << ans << endl;
    return 0;
}

C.情人节的倍数

解题思路

很简单的,是从18位位数来考虑倍数,
选数字的规则很明确,520x520x...x为任意一个数
最小,也即搜索的情况是x从0->9即可
应对条件:数字长度18和格式,
搜索中用一个参数表示长度即可,输出中直接左对齐格式输出
注意搜不到答案的时候ans为0和长整型数据就可以解决这个题了

Code

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
ll n,ans;
void dfs(ll x,int y,int z)//x为当前数字,y为数字位数,z为将选用数字 
{
    if(y>18)return ;
    if(x%n==0&&x)
    {
        ans=x;
        return ;
    }
    if(z==3)
    {
        for(int i=0;i<=9;++i)
            dfs(x*10+i,y+1,0); 
    }
    else
    {
        if(z==0)x=x*10+5;
        else if(z==1)x=x*10+2;
        else x=x*10+0;
        dfs(x,y+1,z+1);
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ans=0;
        scanf("%lld",&n);
        dfs(0,0,0);
        if(ans%n||ans==0)puts("5201314");
        else printf("%-18lldLOVE\n",ans); 
        // 用%-18lld格数简单处理格式问题 
    }
    return 0;
} 

D.像素游戏

解题思路

S串中实际下标 0 1 2 3 4 5 6 7 8 9
每一个字母的5行对应S串中的数字序号构成一个数组 (为方便,这里公用第一个下标0用数字0占去)
模拟大法可好了,
分析每一个字母的构造建立一个通用的字符串数组S
接着用每一个字母的5行结构写一个转译数组code
得到字符串时,将 当前字母的 5个code数 对应于S字符串中 添加到 ans字符串中
最后直接每行输出ans字符串数组即可

Code

#include<bits/stdc++.h>
using namespace std;
#define N 1000
bool mp[N][N];
int code[][6]={{0,1,3,9,4,4},{0,6,4,6,4,6},{0,7,2,2,2,7},{0,6,4,4,4,6},{0,9,2,9,2,9},{0,9,2,9,2,2},{0,5,2,8,4,5},{0,4,4,9,4,4}};
char S[][7]={"      ","  o   ","o     "," o o  ","o   o "," ooo  ","oooo  "," oooo ","o ooo ","ooooo "};
/*
S串中实际下标 0        1        2        3        4        5        6        7        8        9
每一个字母的5行对应S串中的数字序号构成一个数组 (为方便,这里公用第一个下标0用数字0占去) 
模拟大法可好了,
分析每一个字母的构造建立一个通用的字符串数组S
接着用每一个字母的5行结构写一个转译数组code
得到字符串时,将 当前字母的 5个code数 对应于S字符串中 添加到 ans字符串中
最后直接每行输出ans字符串数组即可 
*/

char s[N];
char ans[6][100];
/*
  o  
 o o 
ooooo
o   o
o   o

oooo
o   o
oooo
o   o
oooo

 oooo
o    
o
o
 oooo

oooo
o   o
o   o
o   o
oooo

ooooo
o
ooooo
o
ooooo

ooooo
o
ooooo
o
o

 ooo
o   
o ooo
o   o
 ooo

o   o
o   o
ooooo
o   o
o   o
*/
int main()
{
    scanf("%s",&s);
    memset(ans,0,sizeof ans);
    for(int i=0;s[i];++i)//每个字母 
    {
        for(int k=1;k<=5;++k)//5层 
        {
            strcat(ans[k],S[code[s[i]-'a'][k]]);//可以不使用strcat函数写源代码,自学 
        }
    }
    for(int i=1;i<=5;++i)puts(ans[i]); 
    return 0;
} 

E.孤独的数字(easy)

解题思路:

其实这道题比后面那个题难,是我虚晃一枪,hh

我们用map标记一下出现过的前缀和(或者叫子序列),然后一旦发现有相等的,那么必然会存在相加为0的情况,这个时候就需要插入一个数,这个数假设就去INF,反正就不让它为0,然后将map存储的前缀和信息清空,从当前位置作为第一个元素继续前缀和,注意的是,每次清空需要将map[0]标记为true

Code

#include
using namespace std;
#define ll long long

const int N = 200005;

map mp;
int a[N];

int main()
{
    int n;
    ll sum = 0;
    scanf("%d",&n);
    mp[0] = true;
    int ans = 0;
    for(int i = 0;i < n; ++i) {
        scanf("%d",&a[i]);
        sum += a[i];
        if(mp[sum]) {
            mp.clear();
            ans ++;
            sum = a[i];
            mp[0] = true;
        }
        mp[sum] = true;
    }
    printf("%d\n",ans);
    return 0;
}

F.孤独的数字(hard)

解题思路

很明显我们能看出当连续的两个数之和小于十那么就需要添加一个数字,这个数字可以直接取正无穷,所以答案就是相邻的两个数之和小于十的个数

Code

#include
using namespace std;

const int N = 1000005;
int n,t;
int a[N];

int main()
{
    scanf("%d",&t);
    while(t--) {
        scanf("%d",&n);
        int ans = 0;
        for(int i = 0;i < n; ++i) {
            scanf("%d",&a[i]);
            if(i > 0 && a[i]+a[i-1] < 10) {
                ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

G.彩虹屁

解题思路

给大家放松的题目^^,标程是从提交AC随机抽取的

Code

#include
int main()
{
    printf("实验室环境很好,学习氛围很浓厚,不论是acm队长还是队员都乐于助人,帮助萌新,大家互相探讨问题,研究题目时的热情都很浓烈.\n");
    printf("这次竞赛题目灵活有趣,既照顾了新人又不失挑战性,可见出题人的良苦用心,不仅锻炼大家的思维能力又激起大家探究问题的热情.\n");
    printf("语文不好写不出来了"); 
    return 0;
}

#include 
using namespace std;
int main()
{
    cout<<"Acm团队真的太好了,在这里不仅可以学到很多知识,还能遇到许多小伙伴,但是最重要的是可以遇见我们亲爱的谢队,真的是太好了,爱死谢队了,谢队不仅人超级好,而且代码敲的好,人也长得帅,要是我是个女生,我一定要嫁给他,啊,我对谢队的爱犹如江海一样在我心中波涌,能和谢队在一个实验室,实在是三生有幸,太好了啊谢队。同时,acm实验室真的太棒了,有热水,有空调,条件真的杠杠的,舒适安逸,是个学习的好地方,真是太高兴了能够在acm里面学习" <

H.无相连通图

解题思路

最短路板子题

Code

#include
using namespace std; 
typedef long long ll;
#define N 100009
#define INF 0x3f3f3f3f
#define mt(x) memset(x,0,sizeof x) 
int n,m,s,dis[N],vis[N],head[N],num;
/*
图论经典 
最短路模板题
因为点数太大,就得链式向前星 
*/ 
struct iii
{
    int to,next,dis;
}mp[N];
struct ii
{
    int dis,pos;
    bool operator <(const ii &x)const
    {
        return x.disq;
void add(int x,int y,int z)
{
    mp[++num].dis=z;
    mp[num].to=y;
    mp[num].next=head[x];
    head[x]=num;
}
void Dijkstra()
{
    dis[s]=0;
    q.push((ii){0,s});
    while(q.size())
    {
        ii now=q.top();
        q.pop();
        int x=now.pos,y;
        if(vis[x])continue;
        vis[x]=1;
        for(int i=head[x];i;i=mp[i].next)
        {
            y=mp[i].to;
            if(dis[y]>dis[x]+mp[i].dis)
            {
                dis[y]=dis[x]+mp[i].dis;
                if(!vis[y])q.push((ii){dis[y],y});
            }
        }
    }
}
int main()
{ 
    num=0;
    scanf("%d %d %d",&n,&m,&s);
    for(int i=1;i<=n;++i)dis[i]=INF;
    mt(head);mt(vis);mt(mp);
    for(int i=1;i<=m;++i)
    {
        int x,y,z;
        scanf("%d %d %d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    Dijkstra();
    for(int i=1;i<=n;++i)
        printf("%d ",dis[i]);
    return 0;
}

I.呐!你的签到题

解题思路

维护这个公式的线段树,详情请看代码

Code

#include
#include
#include

using namespace std;

#define ll long long

const int N = 200010;

ll tree[N<<2],x[N];

void push_up(int k) {
    tree[k] = max(tree[k*2],tree[k*2+1]);
}

void build(int l,int r,int k) {
    if(l == r) {
        tree[k] = x[l+1] - x[l];
        return;
    }
    int mid = l + r >> 1;
    build(l,mid,k<<1);
    build(mid+1,r,(k<<1)+1);
    push_up(k);
}

void updata(int l,int r,int k,int a,ll b) {
    if(l == r) {
        tree[k] = b;
        return;
    }
    int mid = l + r >> 1;
    if(a <= mid)
        updata(l,mid,k*2,a,b);
    else
        updata(mid+1,r,k*2+1,a,b);
    push_up(k);
}



int main()
{

    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n; ++i) {
        scanf("%lld",&x[i]);
    }
    build(1,n-1,1);
    while(m--) {
        int a;
        ll b;
        scanf("%d%lld",&a,&b);
        x[a] = b;
        if(a > 1)
            updata(1,n-1,1,a-1,x[a]-x[a-1]);
        if(a < n)
            updata(1,n-1,1,a,x[a+1]-x[a]);
        printf("%lld\n",tree[1]);
    }

    return 0;
}
/*
    ┏┛ ┻━━━━━┛ ┻┓
    ┃      ┃
    ┃   ━         ┃
    ┃ ┳┛   ┗┳     ┃
    ┃             ┃
    ┃   ┻       ┃
    ┃            ┃
    ┗━┓   ┏━━━┛
      ┃   ┃   神兽保佑
      ┃   ┃   代码无BUG!
      ┃   ┗━━━━━━━━━┓
      ┃           ┣┓
      ┃             ┏┛
      ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛
          ┃ ┫ ┫   ┃ ┫ ┫
          ┗━┻━┛   ┗━┻━┛
*/

J.一键三连

解题思路

Code

#include
#include
#define mt(x) memset(x,0,sizeof x)
/*
1 2 3
4 5 6
7 8 9 
*/ 
bool a[10]; 
bool pd(int x,int y,int z)
{
    mt(a);//清空初始化 
    /*
    不可连的种类,只有连了一点而重复连的情况
    且只考虑前两个数字对第三个数字的限制

    如此,可以简单使用分支结构来确定答案
    这里用数组处理

    对应的有
    13/31连2
    46/64连5
    79/97连8

    17/71连4
    28/82连5
    39/93连6 

    还有19/91连5和37/73连5 
    */
    a[x]=1;a[y]=1;
    if(x==y)return false;//特别处理相等 
    if(a[1]&&a[3])     a[2]=1;
    else if(a[4]&&a[6])a[5]=1;
    else if(a[7]&&a[9])a[8]=1;

    else if(a[1]&&a[7])a[4]=1;
    else if(a[2]&&a[8])a[5]=1;
    else if(a[3]&&a[9])a[6]=1;

    else if(a[1]&&a[9])a[5]=1;
    else if(a[3]&&a[7])a[5]=1; 
    return a[z]?false:true;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int x,y,z;
        scanf("%d %d %d",&x,&y,&z);
        puts(pd(x,y,z)?"yes!":"no!");
    }
    return 0;
} 

K.简单的脑筋急转弯

解题思路

Code

#include
using namespace std;
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int a[3];
        scanf("%d %d %d",&a[0],&a[1],&a[2]);
        sort(a, a + 3);
        if(a[0]==a[1]&&a[0]==a[2]&&a[1]==a[2]){
            printf("YES\n");
            continue;
        }
        else if(a[0]!=a[1]&&a[0]!=a[2]&&a[1]!=a[2]){
                printf("NO\n");
                continue;
        }
        else if(a[0]==a[1]){
           printf("NO\n");
           continue;
        }
        else{
            printf("YES\n");
            continue;
         } 
    return 0;

    }
}

L.他在第几层?

解题思路

Code

#include
using namespace std;
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int n,x;
        int ans=0;
        scanf("%d %d",&n,&x);
        if(n==1||n==2){
            printf("1\n");
            continue;
        }
        n=n-2;
        if(n%x) {
        x=n/x;
        ans=x+2;
        printf("%d\n",ans);
        continue;
        }
        x=n/x;
        ans=x+1;
        printf("%d\n",ans);
    }
    return 0;
}


本当の声を響かせてよ