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.方格移動
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;
}