武汉工程大学计算机科学与工程学院第二届程序设计新生赛 解题报告 Apare_xzc

武汉工程大学计算机科学与工程学院第二届程序设计新生赛 解题报告

xzc 2020.3.13


在这里插入图片描述

链接:武汉工程大学计算机科学与工程学院第二届程序设计新生赛 <–

序言:

        这套题质量还不错。可以感觉到出题人的用心设计。考察了乘法逆元,快速幂,并查集,dp,线段树等知识点。虽然对于新生来说可能大部分人还没有学过这些知识点,但是都考察得很基础。这种比塞题对于后续的学习还是很有益处的。


A. Hello, algorithm(86/175)

在这里插入图片描述

分析:

        我们想AC,当然是输出“AC”了。

代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
	cout<<"AC\n";
	return 0;	
} 

B. 等闲变却故人心(30/106)

在这里插入图片描述

样例输入:

3 3
...
.*.

样例输出:

4

分析:

        简单bfs,从起点开始bfs,最后一个入队的点即为最远的点。从起点到这个点的步数即为所求。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1003;
char a[N][N];
bool vis[N][N];
int m,n;
struct Node{
    int x,y,step;
    Node(int xx=0,int yy=0,int s=0):x(xx),y(yy),step(s){}
}node;
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
void bfs()
{
    int x,y,xx,yy,step;
    queue<Node> Q;
    Q.push(Node(1,1,0));
    vis[1][1] = true;
    int ans = 0;
    while(!Q.empty())
    {
        node = Q.front();Q.pop();
        x = node.x, y = node.y, step = node.step;
        ans = step;
        for(int i=0;i<4;++i)
        {
            xx = x+dx[i], yy = y+dy[i];
            if(vis[xx][yy]||a[xx][yy]!='.') continue;
            Q.push(Node(xx,yy,step+1));
            vis[xx][yy] = true;
        }
    }
    cout<<ans<<endl;
 
}
int main()
{  
    cin>>n>>m;
    memset(a,'*',sizeof(a));
    for(int i=1;i<=n;++i)
        scanf("%s",a[i]+1),a[i][m+1]='*';
    bfs();
    return 0;  
}

C. Rie(1/4)

在这里插入图片描述

分析:

        这题是模拟一个简单编译器。比赛的时候1/4,没做,跳过了。


D. 所有的相遇,都不过是离别的序曲(5/32)

在这里插入图片描述

分析:

        这题觉得有规律,但是不好找。应该就是个结论题吧。我本来想dp递推一下,推个几百天说不定就够精度了,后来好像也不保险,而且多组输入,复杂度也太高。这题应该说是个概率的结论吧,答案就是min(1,p/(1-p))

代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int T;
	double p,q;
	cin>>T;
	while(T--)
	{
		scanf("%lf",&p);
		q = 1-p;
		printf("%.6f\n",min(1.0,p/q));	
	}	
	return 0;
} 

E. 夜雨江湖无故旧(5/15)

在这里插入图片描述

样例输入:

1
233 2333 23333 233333

样例输出:

2322931

分析:

        按照题意,求x = a^b, y = c^d, x乘以y关于mod的逆元即可。

代码:

#include <bits/stdc++.h>
using namespace std;
const int mod = 20190930;
typedef long long LL;
LL fast_pow(LL a,LL b,LL m)
{
    if(a==b) return 0;
    LL ans = 1;
    while(b)
    {
        if(b&1) ans = ans*a%m;
        a = a*a%m;
        b>>=1;       
    }
    return ans;
}
void exgcd(LL a,LL b,LL& d,LL&x,LL&y)
{
    if(b==0) {
        d = a; x = 1; y = 0;return;
    } exgcd(b,a%b,d,y,x);
    y -= (a/b)*x;
}
LL getNi(LL a,LL b)
{
    LL d,x,y;
    exgcd(a,b,d,x,y);
    return (x%b+b)%b;
}
int main()
{
    LL a,b,c,d,t;
    cin>>t;
    while(t--)
    {
        cin>>a>>b>>c>>d;
        a = fast_pow(a,b,mod);
        c = fast_pow(c,d,mod);
        c = getNi(c,mod);  
        a = a*c%mod;
        cout<<a<<endl;
    }  
    return 0;
 }

F. 朋友圈(11/59)

在这里插入图片描述

样例输入:

5 2
1 3
3 5

样例输出:

3 1 3 1 3

分析:

        用并查集维护朋友关系,然后输出每个人所在集合的人数即可。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int pre[maxn],cnt[maxn];
void initUFset(int n)
{
    for(int i=1;i<=n;++i)
        pre[i] = i;
}
int Find(int x)
{
    return x==pre[x]?x:pre[x]=Find(pre[x]);
}
void join(int x,int y)
{
    int fx = Find(x), fy = Find(y);
    if(fx!=fy) pre[fy] = fx;
}
int main()
{
    int n,m,x,y;
    cin>>n>>m;
    initUFset(n);
    while(m--) {
        scanf("%d%d",&x,&y),
        join(x,y);
    }
    for(int i=1;i<=n;++i)
        ++cnt[Find(i)];
    for(int i=1;i<=n;++i)
        printf("%d%c",cnt[Find(i)],i==n?'\n':' ');
    return 0;
}

G. 肥宅快乐水(66/301)

在这里插入图片描述

样例输入:

2 4 5

样例输出:

60

分析:

        显然,求所有人数的最小公倍数,然后乘以n即可。lcm(a,b) = a * b / gcd(a,b), gcd可以用欧几里得原理求,也可以用g++的__gcd()函数

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL gcd(LL a,LL b)
{
	return (b==0)?a:gcd(b,a%b);
}
LL lcm(LL a,LL b)
{
	return a/gcd(a,b)*b;
}
int main()
{
	LL a,b,c;
	cin>>a>>b>>c;
	a = lcm(a,b);
	a = lcm(a,c);
	cout<<a*3<<endl; 
	return 0; 
} 

H. 跳格子(11/24)

在这里插入图片描述

样例输入:

2
6 2 3
1 2 3 4 5 6
5 3 3
1 2 3 4 5

样例输出:

11
-1

分析:

        显然是dp。dp[x] = max(dp[x-s],dp[x-(s+1)],dp[x-(s+1)], ... , dp[x-t])+v[x]

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int v[N],dp[N],s,t;
int main()
{
    int T,n,s,t;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&s,&t);
        for(int i=1;i<=n;++i)
            scanf("%d",&v[i]);
        memset(dp,-1,sizeof(int)*(n+1));
        dp[1] = v[1];
        for(int i=2;i<=n;++i)
        {
            for(int j=s;j<=t;++j)
            {
                if(i<=j||dp[i-j]==-1) continue;
                dp[i] = max(dp[i],dp[i-j]+v[i]);
            }
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}

I. 大炼丹师(73/172)

在这里插入图片描述

样例输入:

4
3 3 3
3 4 5
2 2 3
1 2 3

样例输出:

equilateral
right
normal
error

分析:

        可以先对边长排序,这样好写。

代码:

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int a[3],T;
    scanf("%d",&T);
    while(T--) {
        for(int i=0;i<3;++i)
            scanf("%d",a+i);
        sort(a,a+3);
        if(a[0]+a[1]<=a[2]) {
            puts("error");
        } else if(a[0]==a[2]) {
            puts("equilateral");
        } else if(a[0]*a[0]==a[2]*a[2]-a[1]*a[1]) {
            puts("right");
        } else {
            puts("normal");
        }
    }  
    return 0;
}

J. 辞旧迎新(26/180)

在这里插入图片描述

样例输入:

helloworld
reverie

样例输出:

eeeeirorld

分析:

        贪心即可。对t排序,对字符串s,从前往后,如果比t当前最小的字符大,就替换掉。

代码:

#include <bits/stdc++.h>
using namespace std;
char s[100005],t[100005];
int main(void) {
    int lens,lent;
    scanf("%s%s",s,t);
    lens = strlen(s), lent = strlen(t);
    sort(t,t+lent);
    int p = 0;
    for(int i=0;i<lens&&p<lent;++i)
        if(s[i]>t[p]) s[i] = t[p++];
    puts(s);
    return 0;
}

K. 麦田守望者(2/17)

在这里插入图片描述
在这里插入图片描述

样例输入:

5 3
1 2 3 4 5
2 1 5
1 2 4
2 1 5

样例输出:

3
5

分析:

        显然可以用线段树维护。我们用线段树维护区间最大值。题目是单点更新,所以不需要lazy标记。
        查询区间最大值的时候,直接从线段树的根节点往下查即可。查询区间中第一个大于给定值的位置时,我们可以先从线段树根节点往下递归,若在查询区间范围内,优先查询左子树。

代码:

#include <bits/stdc++.h>
#define Lson left,mid,pos<<1
#define Rson mid+1,right,pos<<1|1
using namespace std;
const int N = 5E5+3;
const double e = 2.7182818;
int a[N],Max[N<<2];
int build(int left,int right,int pos) {
    if(left==right) return Max[pos] = a[left];
    int mid = (left+right)/2;
    return Max[pos] = max(build(Lson),build(Rson));
}
int modify(int left,int right,int pos,int x,int val) {
    if(left>x||right<x) return Max[pos];
    if(left==right) return a[left] = Max[pos] = val;
    int mid = (left+right)/2;
    return Max[pos] = max(modify(Lson,x,val),modify(Rson,x,val));
}
int query(int left,int right,int pos,int qL,int qR)
{
    if(qL>right||qR<left) return -1000000000;
    if(qL<=left&&right<=qR) return Max[pos];
    int mid = (left+right)/2;
    return max(query(Lson,qL,qR),query(Rson,qL,qR));
}
int Query(int left,int right,int pos,int qL,int qR,int v)
{
    if(left>qR||right<qL||Max[pos]<=v) return 10000000; //不在所求的范围之内
    if(left==right) return left;
    int mid = (left+right)/2;
    if(qL<=left&&right<=qR)
    {
        if(Max[pos<<1]>v) return Query(left,mid,pos<<1,qL,qR,v);
        else return Query(mid+1,right,pos<<1|1,qL,qR,v);
    }
    int idL = Query(left,mid,pos<<1,qL,qR,v);
    int idR = Query(mid+1,right,pos<<1|1,qL,qR,v);
    return min(idL,idR);
}
int main()
{
    int n,q,x,v,l,r,op,m,Lmax,Rmax,id;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;++i)
        scanf("%d",a+i);
    build(1,n,1);
    while(q--)
    {
        scanf("%d",&op);
        if(op==1) {
            scanf("%d%d",&x,&v);
            modify(1,n,1,x,v);
        } else {
            scanf("%d%d",&l,&r);
            if(l==r) {
                printf("%d\n",a[r]);continue;
            } m = l+floor(1.0*(r-l+1)/e);
            Lmax = query(1,n,1,l,m);
            Rmax = query(1,n,1,m+1,r);
            if(Rmax<=Lmax) id = r;
            else id = Query(1,n,1,m+1,r,Lmax);
            printf("%d\n",a[id]);
        }
    }  
    return 0;
}

2020/3/13
13:58
xzc


猜你喜欢

转载自blog.csdn.net/qq_40531479/article/details/104834734