1. 程式人生 > 其它 >2022合肥學院ACM程式設計大賽-正式賽題解

2022合肥學院ACM程式設計大賽-正式賽題解

A.孤獨搖滾

計算下一個迴文年,輸出即可。

#include<stdio.h>
int check(int x)
{
    if(x/1000==x%10&&x/100%10==x%100/10)
        return 1;
    return 0;
}
int main()
{
    for(int i=2022;;i++)
        if(check(i))
        {
            printf("%d",i);
            break;
        }
    return 0;
}

B.苦痛之路

構造方式不唯一,滿足題意即可,給下面給出一種構造方法。

#include<stdio.h>
long long  a,b,c;
int main()
{
    scanf("%d%d%d",&a,&b,&c);
    printf("%lld %lld %lld",a+b+c,b+c,c);
    return 0;
}

C.淺淺的下個五子棋

列舉棋盤的每個位置,檢查一下是否存在4子即可。注意要判斷一下是否會訪問越界。

成四子的方法無非就是橫著,豎著,正對角線,反對角線

#include<stdio.h>
int a[510][510], n, cnt = 0;
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            scanf("%d", &a[i][j]);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {
            if (a[i][j] == 1 && a[i + 1][j + 1] == 1 && a[i + 2][j + 2] == 1 && a[i + 3][j + 3] == 1)
            {
                cnt ++;
                break;
            }
            if (a[i][j] == 1 && a[i][j + 1] == 1 && a[i][j + 2] == 1 && a[i][j + 3] == 1)
            {
                cnt ++;
                break;
            }
            if (a[i][j] == 1 && a[i + 1][j] == 1 && a[i + 2][j] == 1 && a[i + 3][j] == 1)
            {
                cnt ++;
                break;
            }
            if (i - 3 >= 1 && a[i][j] == 1 && a[i - 1][j + 1] == 1 && a[i - 2][j + 2] == 1 && a[i - 3][j + 3] == 1)
            {
                cnt ++;
                break;
            }
        }
    if (cnt == 0)
        printf("123456");
    else
        printf("114514");
    return 0;
}

D.方格移動

題解傳送門:https://zhuanlan.zhihu.com/p/585838659?utm_campaign=&utm_medium=social&utm_oi=1491769876256096256&utm_psn=1583199367946731520&utm_source=qq

E.冠軍小智的寶可夢盒子

小智終於拿冠軍了,太不容易了。從寶可夢動畫播出到現在已經25年了,終於看到他拿了冠軍了!

雖然他冠軍拿的十分困難,但是這題一點都不難,你用map,用vector,用啥都可以。

我這邊給一個不用標準庫容器的版本,思路是將二維轉一維。因為固定的二維可能會炸。

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n,m,q;
int a[N];
int &my_get(int i,int j)
{
    return a[(i-1)*m+j];
}
int main()
{
    cin>>n>>m;
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j)
            cin>>my_get(i,j);
    cin>>q;
    while (q--)
    {
        int x,y;
        cin>>x>>y;
        if (my_get(x,y)) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

你問函式前面為什麼帶一個&,這個吧,emmmmmmmm,詳見C++的引用。

F.完美的數

二進位制數中k + 1個連續的 1 可以由 \(2^{k} - 1\)得到

二進位制數中k個連續的0可以由 \(2^{k - 1}\)得到

兩者相乘即可得到二進位制數中存在連續k + 1個1和連續k個0

可以得到公式$(2^{k} - 1) * 2^{k - 1} $

當然也可以暴力求解

在一個二進位制數後面填1相當於對這個數乘2 再加 1

在一個二進位制數後面填0相當於對這個數乘2

下面是第一種方法的程式碼

// c

#include <stdio.h>

int q[32]; //存 2^k
int main()
{
    //求出2^i
    q[0] = 1;
    for(int i = 1; i <= 31; i ++)
        q[i] = q[i - 1] * 2;
    
    int ans = 0;

    int n ;
    scanf("%d", &n);
    for(int k = 1; ; k ++)
    {
        if((q[k] - 1) * q[k - 1] <= n)
            ans = (q[k] - 1) * q[k - 1];
        else
            break;
    }

    printf("%d\n", ans);
}

第二種方法

// c
#include <stdio.h>
int main()
{
    int ans = 0;
    int n;
    scanf("%d", &n);
    for(int k = 0; ; k ++)
    {
        int res = 0;
        //往0後面加(k + 1)個1
        for(int i = 1; i <= k + 1; i ++)
            res = res * 2 + 1;
        
        //往(k+1)個1後面加k個0
        for(int i = 1; i <= k; i ++)
            res = res * 2;
        
        //如果得到的值小於等於n則更新答案
        if(res <= n)
            ans = res;
        else break;
    }

    printf("%d\n", ans);
}

G. 國足怎麼能進世界盃?

簽到題

讀入上底a, 下底b, 高h

由梯形面積公式 (a + b) * h / 2

可以得到答案

程式碼如下

// C;
#include <stdio.h>

int main()
{
    int a, b, h;
    scanf("%d%d%d", &a, &b, &h);
    
    printf("%d\n", (a + b) * h / 2);

    return 0;
}

H.我真的不是小黑子

我真的不是小黑子,真的!

沒寫C++的標準程式,這裡用一下新生校賽第一的程式碼

#include<bits/stdc++.h>
using namespace std;
int p[1000];
int main()
{
	long long a,b;
	cin>>a>>b;
	long long sum,y,cnt=0,j;
	sum=a*b;
	for(y=sum;y>0;cnt++)
        y/=10;
	long long ans,l=1;
	for(j=0;j<cnt;j++)
    {
		p[j]=sum%10;
		sum/=10;
	}
	for(int u=cnt-1;u>=0;u--)
    {
		cout<<p[u];
		if(p[u-1]==0)
            cout<<endl;
		else if(p[u]==0)
            cout<<endl;
	}
	return 0;
}

然後附加一份Python的

A, B = map(int,input().split())
S = str(A * B)
print(S.replace("0", "\n0\n").replace("0\n\n0", "0\n0").strip())

I.同行之路

觀察可以發現,想讓兩個分式相等,最多需要2次操作,分類討論即可。
對於\(\frac{a}{b},\frac{c}{d}\):
如果\(a*d==b*c\),需要0次操作。
如果\((a*d)\%(b*c)==0\),需要1次操作。
如果\((a*d)\%(b*c)!=0\),需要2次操作。
此外還需要特判一下\(b*c\)是否為0。

#include <bits/stdc++.h>
using namespace std;
int main()
{
    long long a, b, c, d;
    cin >> a >> b >> c >> d;
    long long num1 = a * d;
    long long num2 = b * c;
    if (num1 < num2)
        swap(num1, num2);
    if (num1 == num2)
        cout << "0" << endl;
    else
    {
        if (num2 == 0)
            cout << "1" << endl;
        else
        {
            if (num1 % num2 == 0)
                cout << "1" << endl;
            else
                cout << "2" << endl;
        }
    }
    return 0;
}

J.凝冰渡海真君

(轉載某位大佬的題解,A題)https://zhuanlan.zhihu.com/p/561604699

K.重生之我在昨日圓車

因為陣列的每個數都大於0,所以保證字首和沒有相同的值,可以用map來記錄字首和的值是否存在。因此,題目轉化為,是否存在字首和\(x\),使得\(x+p,x+p+q,x+p+q+r\)都存在。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
ll n, p, q, r;
int a[N];
ll sum[N];
map<ll, bool> mp;
void solve()
{
    mp[0] = true;
    cin >> n >> p >> q >> r;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        sum[i] = sum[i - 1] + a[i];
        mp[sum[i]] = true;
    }
    for (int i = 1; i <= n; i++)
        if (sum[i] >= p)
        {
            if (mp[sum[i] - p] && mp[sum[i] + q] && mp[sum[i] + q + r])
            {
                cout << "Yes" << endl;
                return;
            }
        }
    cout << "No" << endl;
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    while (t--)
        solve();
    return 0;
}

L.合大校園錦標賽

首先通過二分答案求出每個校區之間的最小距離,然後對於每個提問和最小距離進行對比

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1001;
int n,k,q;
int x[N],y[N],p[N],idx = 0;
int st[N];
struct E{
    int a,b;
    double v;
    inline bool operator< (const E& e) const {
        return this->v < e.v;
    }
} e[(N+1)*N/2];

int find(int x)
{
    return (p[x]==x?p[x]:p[x]=find(p[x]));
}
//求取兩點距離
double getdis(int a,int b)
{
    return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
void build(int a,int b)
{
    e[idx].a = a;
    e[idx].b = b;
    e[idx++].v = getdis(a,b);
}
int main()
{
    cin>>n>>k;
    for (int i=1;i<=n;++i) cin>>x[i]>>y[i];
    for (int i=1;i<=n;++i)
        for (int j=i+1;j<=n;++j)
            build(i,j);
    sort(e,e+idx);
    double l = 0,r = e[idx-1].v;
    //二分答案求出最短距離
    while (r-l>1e-6)
    {
        double mid = (l+r) / 2;
        for (int i=0;i<=n;++i) p[i] = i;
        for (int i=0;i<idx;++i)
        {
            int a = e[i].a,b = e[i].b;
            double v = e[i].v;
            if (v>mid) break;
            a = find(a),b = find(b);
            if (a!=b)
            {
                p[a] = b;
            }
        }
        memset(st,0,sizeof st);
        int cnt = 0;
        for (int i=1;i<=n;++i)
            if (!st[find(i)]) st[find(i)]=true,cnt ++;
        if (cnt >= k)
            l = mid;
        else
            r = mid;
    }
    cin>>q;
    for (int i=1;i<=q;++i)
    {
        int a,b;
        cin>>a>>b;
        if (getdis(a,b)<=l) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}

M.大慈樹王的樹

本題涉及高階資料結構——線段樹,新生看看就行()。

題意:給你一棵樹,每個點都有一個權值,將詢問q次,每次詢問將x點的權值改為y,或詢問m個點,需要輸出這m個點子樹中點的並集的積

分析:考慮dfs序,用dfs序的開始和結尾表示每個點代表的區間,用線段樹維護每個區間的值的積,只需單修區查即可,每次詢問m個點將區間記下來,跑一遍區間合併,然後將求合併後的區間的積即可

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10, M = 4010,mod = 1e9+7, b1 = 1037, b2 = 1111, p1 = 9999971, p2 = 9999973,inf=1<<30;
const double eps = 1e-10;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> PII;
typedef pair<int,ll> PIL;
struct Node{
	ll val;
} seg[8*N];
int n,q;
ll w[N];
vector<int> e[N];
int stk[N],tot;
int st[N],ed[N];
vector<PII> tmp,res;

void merge(){
	res.clear();
	sort(tmp.begin(),tmp.end());
	tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
	int sta=-2e9,end=-2e9;
	for(auto [i,j] : tmp){
		if(sta == -2e9){
			sta = i;
			end = j;
			continue;
		}
		if(i > end){
			res.push_back({sta,end});
			sta = i;
			end = j;
		}else{
			end = max(j,end);
		}
	}
	res.push_back({sta,end});
}

void dfs(int u,int f){
	st[u] = ++tot;
	stk[tot] = u;
	for(auto v : e[u]) {
		if(v == f) continue;
		dfs(v,u);
	}
	ed[u] = tot;
}

void pushup(int id){
	seg[id].val = seg[2*id].val*seg[2*id+1].val%mod;
}

void build(int id,int l,int r){
	if(l == r){
		seg[id].val = w[stk[l]];
		return ;
	}
	int mid = l + r >> 1;
	build(2*id,l,mid);
	build(2*id+1,mid+1,r);
	pushup(id);
}

void change(int id,int l,int r,int p,ll x){
	if(l == r && l == p){
		seg[id].val = x;
		return ;
	}
	int mid = l + r >> 1;
	if(mid>=p) change(2*id,l,mid,p,x);
	else change(2*id+1,mid+1,r,p,x);
	pushup(id);
}

ll query(int id,int l,int r,int ql,int qr){
	if(l == ql && r == qr){
		return seg[id].val;
	}
	int mid = l + r >> 1;
	if(mid>=qr) return query(2*id,l,mid,ql,qr);
	else if(mid<ql) return query(2*id+1,mid+1,r,ql,qr);
	else{
		return query(2*id,l,mid,ql,mid)*query(2*id+1,mid+1,r,mid+1,qr)%mod;
	}
}

void solve(){
	scanf("%d%d",&n,&q);
	for(int i = 1; i <= n; i ++) e[i].clear();
	tot = 0;
	for(int i = 1; i < n; i ++) {
		int u,v;
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dfs(1,0);
	for(int i = 1; i <= n; i ++) scanf("%lld",&w[i]);
	build(1,1,n);
	while(q --){
		ll op,x,y;
		scanf("%lld%lld",&op,&x);
		if(op == 1){
			scanf("%lld",&y);
			change(1,1,n,st[x],y);
		}else{
			tmp.clear();
			for(int i = 1; i <= x; i ++){
				int xx;
				scanf("%d",&xx);
				tmp.push_back({st[xx],ed[xx]});
			}
			merge();
			ll ans = 1;
			for(auto [i,j] : res){
				ans = ans*query(1,1,n,i,j)%mod;
			}
			printf("%lld\n",ans);
		}
	}
}

int main()
{
		solve();

    return 0;
}