題目鏈接: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>usingnamespacestd;constint 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();}return0;
}
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;}elseif(n&1) ans = 1;printf("%d\n", ans);}return0;
}
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>usingnamespacestd;constint mod = 10007;
constint 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();}return0;
}
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;}return0;
}
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 即可。
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>usingnamespacestd;constint 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) returntrue;sort(vec.begin(), vec.end());for(int i = 0; i + 2 < vec.size(); ++ i){if(vec[i] + vec[i+1] > vec[i+2]) returntrue;}returnfalse;
}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");}}return0;
}
Problem G: 等凹數字 dp[i][len][pre][up][down][ispa]代表當前第 i 位,長度為 len,上一位是什么,前面是否遞 增過,前面是否遞減過,當前是否符合回文串的性質,然后記憶化搜索