日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2017广东工业大学程序设计竞赛决赛(官方题解)

發布時間:2025/3/19 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2017广东工业大学程序设计竞赛决赛(官方题解) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:http://gdutcode.sinaapp.com/contest.php?cid=1056
Problem A: 兩只老虎
正常的+有耳朵的 = a/2
正常的+有尾巴的 = b
正常的+有耳朵的+有尾巴的 = c/4
正常的 = a/2+b-c/4

#include <iostream> #include <cstdio> #include <algorithm> #include <cstdlib> using namespace std;const int NUM = 1000;void solve() {int a, b, c;scanf("%d%d%d", &a, &b, &c);int ans = a/2+b-c/4;printf("%d\n", ans); }int main() {int T;scanf("%d", &T);while(T--){solve();}return 0; }

Problem B: 占點游戲
令 d = abs(x1-x2)+abs(y1-y2)
首先判斷(n+1)/2 >= d,先手可不可以從一個點走到另一個點 :
如果不可以,則先手可以多得 n&1 分(因為劣勢者可以選擇逃離)
如果可以,考慮 d 的奇偶性:
如果 d 為奇數(先手可以先踩到后手覆蓋過的點):
如果 n 為奇數,先手可以多得 2 分,否則平。
否則(d 為偶數):
如果 n 為奇數,先手可以多得 1 分,否則后手可以多得 1 分。

#include <cstdio> #include <cmath>using namespace std;int main() {int T;scanf("%d", &T);while(T--){int x1, y1, x2, y2, n;scanf("%d%d%d%d%d", &n, &x1, &y1, &x2, &y2);int tot = abs(x1-x2) + abs(y1-y2);int ans = -1;if((n+1)/2 >= tot){if(tot&1){if(n&1) ans = 2;}else ans = 1;}else if(n&1) ans = 1;printf("%d\n", ans);}return 0; }

Problem C: 爬樓梯
先分段考慮:
對于一段 x 階的樓梯,方案數 f(x) = f(x-1)+f(x-2)+f(x-3) (其中 x >= 3),f(0)=1,f(1)=1, f(2) = 2。
那么對于爬 n 層樓,只需要算出每一段的方案數,然后使用乘法原理乘起來即可。

#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib>using namespace std;const int mod = 10007; const int N = 51; int f[N];void solve() {f[0] = 1;for(int i = 1; i < N; ++ i){f[i] = f[i-1];if(i > 1) f[i] += f[i-2];if(i > 2) f[i] += f[i-3];f[i] %= mod;}int n;scanf("%d", &n);int ans = 1;for(int i = 1; i < n; ++ i){int x;scanf("%d", &x);ans = ans*f[x]%mod;}printf("%d\n", ans); }int main() {int T;scanf("%d", &T);while(T--){solve();}return 0; }

Problem D: 只有通過毀滅才能揭示真理
可以知道每 30 秒可以可以爆發一次 c 傷害,每 1 秒造成 b 傷害,那么答案=a*b+a/30*c。

#include <bits/stdc++.h>class Koz { public:int disintegration(int A, int B, int C) {return A * B + A / 10 / 3 * C;} };int main() {Koz koz;int T;scanf("%d", &T);while( T-- ) {int A, B, C;std::cin >> A >> B >> C;std::cout << koz.disintegration(A, B, C) << std::endl;}return 0; }

Problem E: 倒水(Water)
對于 n 瓶一升的水,把他們合并后,最少需要的瓶子數為 n 的二進制中 1 的個數。假
設 n 的二進制中 1 的個數大于 k,那么我們要找到 1 個大于 n 的數,且二進制中 1 的個數等
于 k 的最小的數 m,那么答案為 m-n。
假設 n 二進制中,最右邊的 1 在第 i 位(這里的第幾位是從右往左數的,最右邊為第 0
位),那么假設你加上一個小于 2^i 的數,結果二進制中 1 的個數只會增加,如果加上一個
2^i,則結果二進制中 1 的個數必定不會增加。所以只需要一直加上一個 2^i(這里的 i 表示
的是當前水的總體積的二進制中最右邊的 1 所在的位置)直到結果中 1 的個數等于 k 即可。

#include <iostream>using namespace std;int cal(int n) {int ans = 0;while(n){ans ++;n &= n-1;}return ans; }int lowbit(int n) {return n&-n; }int main() {int T;scanf("%d",&T);while(T--){int n, k;scanf("%d%d", &n, &k);int ans = 0;while(cal(n) > k){ans += lowbit(n);n += lowbit(n);}printf("%d\n", ans);}return 0; }

Problem F: tmk 找三角
假設現在有 n 條線段,假設 n 條邊從小到達排序,如果這 n 條邊中沒有三條可以構成
三角形,那么這 n 條邊必須滿足關系:A[i] >= A[i-2]+A[i-1],這里的 A[i]表示第 i 條邊的大小。
假設 A[i]盡量取最小 A[i]=A[i-2]+A[i-1],且 A[1]=A[2]=1,是不是就是一個斐波那契,也就
是對于一個 n 條邊的集合,如果不存在三條邊能構成一個三角形,那么最長的邊至少為 f[n],
表示斐波那契第 n 項。而題目中 A[i]<1e9,也就是只要 n>50,就必定存在三條邊可以構成一
個三角形,所以我們只需要暴力加入兩點路徑上的邊(如果大于 50,直接 Yes),然后對這
些邊進行排序,枚舉第 i 條邊為最長邊,貪心判斷 A[i]是否小于 A[i-1]+A[i-2]即可。

#include <cstdio> #include <set> #include <cstring> #include <iostream> #include <vector> #include <algorithm> using namespace std;const int N = 1e5+10; int n; int tot, head[N], to[N<<1], nex[N<<1], len[N<<1]; int f[N], dis[N], dep[N];void init() {tot = 0;for(int i = 0; i <= n; ++ i){head[i] = -1;} }void addEdge(int x, int y, int l) {to[tot] = y;len[tot] = l;nex[tot] = head[x];head[x] = tot++; }void dfs(int u, int d) {dep[u] = d;for(int i = head[u]; ~i; i = nex[i]){int v = to[i];if(v == f[u]) continue;dis[v] = len[i];f[v] = u;dfs(v, d+1);} }bool solve(int x, int y) {vector<int> vec;while(vec.size() < 50 && x != y){if(dep[x] < dep[y]){vec.push_back(dis[y]);y = f[y];}else{vec.push_back(dis[x]);x = f[x];}}if(vec.size()>=50) return true;sort(vec.begin(), vec.end());for(int i = 0; i + 2 < vec.size(); ++ i){if(vec[i] + vec[i+1] > vec[i+2]) return true;}return false; }int main() {int T;scanf("%d", &T);while(T--){scanf("%d", &n);init();for(int i = 1; i < n; ++ i){int x, y, l;scanf("%d%d%d", &x, &y, &l);addEdge(x, y, l);addEdge(y, x, l);}dfs(1, 0);int m;scanf("%d", &m);for(int i = 0; i < m; ++ i){int x, y;scanf("%d%d", &x, &y);puts(solve(x, y) ? "Yes" : "No");}}return 0; }

Problem G: 等凹數字
dp[i][len][pre][up][down][ispa]代表當前第 i 位,長度為 len,上一位是什么,前面是否遞
增過,前面是否遞減過,當前是否符合回文串的性質,然后記憶化搜索

#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <time.h> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> using namespace std; long long dp[20][20][10][2][2][2]; int num[20]; int s[20]; long long rec(int i,int pre,int up,int down,int flag,int q,int len,int ispa) {if(i<0)return up&&down&&ispa;if(~dp[i][len][pre][up][down][ispa]&&!flag&&!q)return dp[i][len][pre][up][down][ispa];long long res=0;int o=s[i];for(int j=0;j<10;j++){num[i]=j;if(j>o&&flag)break;if(q)res+=rec(i-1,j,0,0,j<o?0:flag,q&&j==0,len-(q&&j==0),ispa);else if(j==pre){if(ispa&&i<len/2)res+=rec(i-1,j,up,down,j<o?0:flag,q&&j==0,len,j==num[len-i-1]);else res+=rec(i-1,j,up,down,j<o?0:flag,q&&j==0,len,ispa);}else if(j>pre){if(!down)continue;if(ispa&&i<len/2)res+=rec(i-1,j,1,down,j<o?0:flag,q&&j==0,len,j==num[len-i-1]);else res+=rec(i-1,j,1,down,j<o?0:flag,q&&j==0,len,ispa);}else if(j<pre){if(up)continue;if(ispa&&i<len/2)res+=rec(i-1,j,up,1,j<o?0:flag,q&&j==0,len,j==num[len-i-1]);else res+=rec(i-1,j,up,1,j<o?0:flag,q&&j==0,len,ispa);}}if(!flag&&!q)dp[i][len][pre][up][down][ispa]=res;return res; } long long cal(long long x) {int len=0;while(x){s[len++]=x%10;x/=10;}return rec(len-1,0,0,0,1,1,len,1); } int main() {memset(dp,-1,sizeof(dp));long long l,r;int t;scanf("%d",&t);while(t--){scanf("%lld%lld",&l,&r);printf("%lld\n",cal(r)-cal(l-1));}return 0; }

Problem H: tmk 買禮物
首先,先對 a[i]從小到大排序,假設對于前 i 個硬幣,我們可以組合成 0~y:
①如果 a[i+1]>y+1,那么從 i+1~n 中任意取硬幣,構成的和都>y+1,所以必定構造不出
y+1,于是答案等于 y。
②如果 a[i+1]<=y+1,那么前 i+1 位可以組合成 0~y+a[i+1]。
所以只需要對硬幣從小到大排序,然后從第一個硬幣枚舉到最后一個硬幣,或者中途有
某個數夠不出來即可得到答案。

#include <iostream> #include <cstdio> #include <algorithm>using namespace std;typedef long long ll;const int maxn = 1e5 + 5;int a[maxn];int main() {int T;scanf("%d", &T);while(T--){int n;scanf("%d", &n);for(int i = 0; i < n; ++i) scanf("%d", &a[i]);sort(a, a + n);ll ans = 0;for(int i = 0; i < n && ans + 1 >= a[i]; ++i) ans += a[i];printf("%lld\n", ans);}return 0; }

轉載于:https://www.cnblogs.com/zxy160/p/7215135.html

總結

以上是生活随笔為你收集整理的2017广东工业大学程序设计竞赛决赛(官方题解)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。