武漢工程大學計算機科學與工程學院第二屆程序設計新生賽 解題報告 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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章